Merge tag '9p-for-5.1' of git://github.com/martinetd/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 17 Mar 2019 16:10:56 +0000 (09:10 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 17 Mar 2019 16:10:56 +0000 (09:10 -0700)
Pull 9p updates from Dominique Martinet:
 "Here is a 9p update for 5.1; there honestly hasn't been much.

  Two fixes (leak on invalid mount argument and possible deadlock on
  i_size update on 32bit smp) and a fall-through warning cleanup"

* tag '9p-for-5.1' of git://github.com/martinetd/linux:
  9p/net: fix memory leak in p9_client_create
  9p: use inode->i_lock to protect i_size_write() under 32-bit
  9p: mark expected switch fall-through

fs/9p/v9fs_vfs.h
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/9p/vfs_super.c
net/9p/client.c
net/9p/trans_xen.c

index 5a0db6d..aaee1e6 100644 (file)
@@ -40,6 +40,9 @@
  */
 #define P9_LOCK_TIMEOUT (30*HZ)
 
+/* flags for v9fs_stat2inode() & v9fs_stat2inode_dotl() */
+#define V9FS_STAT2INODE_KEEP_ISIZE 1
+
 extern struct file_system_type v9fs_fs_type;
 extern const struct address_space_operations v9fs_addr_operations;
 extern const struct file_operations v9fs_file_operations;
@@ -61,8 +64,10 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
                    struct inode *inode, umode_t mode, dev_t);
 void v9fs_evict_inode(struct inode *inode);
 ino_t v9fs_qid2ino(struct p9_qid *qid);
-void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
-void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *);
+void v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
+                     struct super_block *sb, unsigned int flags);
+void v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,
+                          unsigned int flags);
 int v9fs_dir_release(struct inode *inode, struct file *filp);
 int v9fs_file_open(struct inode *inode, struct file *file);
 void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
@@ -83,4 +88,18 @@ static inline void v9fs_invalidate_inode_attr(struct inode *inode)
 }
 
 int v9fs_open_to_dotl_flags(int flags);
+
+static inline void v9fs_i_size_write(struct inode *inode, loff_t i_size)
+{
+       /*
+        * 32-bit need the lock, concurrent updates could break the
+        * sequences and make i_size_read() loop forever.
+        * 64-bit updates are atomic and can skip the locking.
+        */
+       if (sizeof(i_size) > sizeof(long))
+               spin_lock(&inode->i_lock);
+       i_size_write(inode, i_size);
+       if (sizeof(i_size) > sizeof(long))
+               spin_unlock(&inode->i_lock);
+}
 #endif
index a25efa7..9a11253 100644 (file)
@@ -446,7 +446,11 @@ v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
                i_size = i_size_read(inode);
                if (iocb->ki_pos > i_size) {
                        inode_add_bytes(inode, iocb->ki_pos - i_size);
-                       i_size_write(inode, iocb->ki_pos);
+                       /*
+                        * Need to serialize against i_size_write() in
+                        * v9fs_stat2inode()
+                        */
+                       v9fs_i_size_write(inode, iocb->ki_pos);
                }
                return retval;
        }
index 85ff859..72b779b 100644 (file)
@@ -538,7 +538,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
        if (retval)
                goto error;
 
-       v9fs_stat2inode(st, inode, sb);
+       v9fs_stat2inode(st, inode, sb, 0);
        v9fs_cache_inode_get_cookie(inode);
        unlock_new_inode(inode);
        return inode;
@@ -1092,7 +1092,7 @@ v9fs_vfs_getattr(const struct path *path, struct kstat *stat,
        if (IS_ERR(st))
                return PTR_ERR(st);
 
-       v9fs_stat2inode(st, d_inode(dentry), dentry->d_sb);
+       v9fs_stat2inode(st, d_inode(dentry), dentry->d_sb, 0);
        generic_fillattr(d_inode(dentry), stat);
 
        p9stat_free(st);
@@ -1170,12 +1170,13 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
  * @stat: Plan 9 metadata (mistat) structure
  * @inode: inode to populate
  * @sb: superblock of filesystem
+ * @flags: control flags (e.g. V9FS_STAT2INODE_KEEP_ISIZE)
  *
  */
 
 void
 v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
-       struct super_block *sb)
+                struct super_block *sb, unsigned int flags)
 {
        umode_t mode;
        char ext[32];
@@ -1216,10 +1217,11 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
        mode = p9mode2perm(v9ses, stat);
        mode |= inode->i_mode & ~S_IALLUGO;
        inode->i_mode = mode;
-       i_size_write(inode, stat->length);
 
+       if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))
+               v9fs_i_size_write(inode, stat->length);
        /* not real number of blocks, but 512 byte ones ... */
-       inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
+       inode->i_blocks = (stat->length + 512 - 1) >> 9;
        v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
 }
 
@@ -1416,9 +1418,9 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
 {
        int umode;
        dev_t rdev;
-       loff_t i_size;
        struct p9_wstat *st;
        struct v9fs_session_info *v9ses;
+       unsigned int flags;
 
        v9ses = v9fs_inode2v9ses(inode);
        st = p9_client_stat(fid);
@@ -1431,16 +1433,13 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
        if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
                goto out;
 
-       spin_lock(&inode->i_lock);
        /*
         * We don't want to refresh inode->i_size,
         * because we may have cached data
         */
-       i_size = inode->i_size;
-       v9fs_stat2inode(st, inode, inode->i_sb);
-       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
-               inode->i_size = i_size;
-       spin_unlock(&inode->i_lock);
+       flags = (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) ?
+               V9FS_STAT2INODE_KEEP_ISIZE : 0;
+       v9fs_stat2inode(st, inode, inode->i_sb, flags);
 out:
        p9stat_free(st);
        kfree(st);
index 4823e1c..a950a92 100644 (file)
@@ -143,7 +143,7 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
        if (retval)
                goto error;
 
-       v9fs_stat2inode_dotl(st, inode);
+       v9fs_stat2inode_dotl(st, inode, 0);
        v9fs_cache_inode_get_cookie(inode);
        retval = v9fs_get_acl(inode, fid);
        if (retval)
@@ -496,7 +496,7 @@ v9fs_vfs_getattr_dotl(const struct path *path, struct kstat *stat,
        if (IS_ERR(st))
                return PTR_ERR(st);
 
-       v9fs_stat2inode_dotl(st, d_inode(dentry));
+       v9fs_stat2inode_dotl(st, d_inode(dentry), 0);
        generic_fillattr(d_inode(dentry), stat);
        /* Change block size to what the server returned */
        stat->blksize = st->st_blksize;
@@ -607,11 +607,13 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
  * v9fs_stat2inode_dotl - populate an inode structure with stat info
  * @stat: stat structure
  * @inode: inode to populate
+ * @flags: ctrl flags (e.g. V9FS_STAT2INODE_KEEP_ISIZE)
  *
  */
 
 void
-v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
+v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,
+                     unsigned int flags)
 {
        umode_t mode;
        struct v9fs_inode *v9inode = V9FS_I(inode);
@@ -631,7 +633,8 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
                mode |= inode->i_mode & ~S_IALLUGO;
                inode->i_mode = mode;
 
-               i_size_write(inode, stat->st_size);
+               if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))
+                       v9fs_i_size_write(inode, stat->st_size);
                inode->i_blocks = stat->st_blocks;
        } else {
                if (stat->st_result_mask & P9_STATS_ATIME) {
@@ -661,8 +664,9 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
                }
                if (stat->st_result_mask & P9_STATS_RDEV)
                        inode->i_rdev = new_decode_dev(stat->st_rdev);
-               if (stat->st_result_mask & P9_STATS_SIZE)
-                       i_size_write(inode, stat->st_size);
+               if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE) &&
+                   stat->st_result_mask & P9_STATS_SIZE)
+                       v9fs_i_size_write(inode, stat->st_size);
                if (stat->st_result_mask & P9_STATS_BLOCKS)
                        inode->i_blocks = stat->st_blocks;
        }
@@ -928,9 +932,9 @@ v9fs_vfs_get_link_dotl(struct dentry *dentry,
 
 int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
 {
-       loff_t i_size;
        struct p9_stat_dotl *st;
        struct v9fs_session_info *v9ses;
+       unsigned int flags;
 
        v9ses = v9fs_inode2v9ses(inode);
        st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
@@ -942,16 +946,13 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
        if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
                goto out;
 
-       spin_lock(&inode->i_lock);
        /*
         * We don't want to refresh inode->i_size,
         * because we may have cached data
         */
-       i_size = inode->i_size;
-       v9fs_stat2inode_dotl(st, inode);
-       if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
-               inode->i_size = i_size;
-       spin_unlock(&inode->i_lock);
+       flags = (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) ?
+               V9FS_STAT2INODE_KEEP_ISIZE : 0;
+       v9fs_stat2inode_dotl(st, inode, flags);
 out:
        kfree(st);
        return 0;
index 10d3bd3..d13d35c 100644 (file)
@@ -172,7 +172,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
                        goto release_sb;
                }
                d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
-               v9fs_stat2inode_dotl(st, d_inode(root));
+               v9fs_stat2inode_dotl(st, d_inode(root), 0);
                kfree(st);
        } else {
                struct p9_wstat *st = NULL;
@@ -183,7 +183,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
                }
 
                d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
-               v9fs_stat2inode(st, d_inode(root), sb);
+               v9fs_stat2inode(st, d_inode(root), sb, 0);
 
                p9stat_free(st);
                kfree(st);
index 357214a..b85d51f 100644 (file)
@@ -1061,7 +1061,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
                p9_debug(P9_DEBUG_ERROR,
                         "Please specify a msize of at least 4k\n");
                err = -EINVAL;
-               goto free_client;
+               goto close_trans;
        }
 
        err = p9_client_version(clnt);
index e2fbf36..29420eb 100644 (file)
@@ -513,7 +513,7 @@ static void xen_9pfs_front_changed(struct xenbus_device *dev,
        case XenbusStateClosed:
                if (dev->state == XenbusStateClosed)
                        break;
-               /* Missed the backend's CLOSING state -- fallthrough */
+               /* fall through - Missed the backend's CLOSING state */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;