Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 21 Feb 2012 00:13:58 +0000 (16:13 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 21 Feb 2012 00:13:58 +0000 (16:13 -0800)
Assorted fixes, sat in -next for a week or so...

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  ocfs2: deal with wraparounds of i_nlink in ocfs2_rename()
  vfs: fix compat_sys_stat() handling of overflows in st_nlink
  quota: Fix deadlock with suspend and quotas
  vfs: Provide function to get superblock and wait for it to thaw
  vfs: fix panic in __d_lookup() with high dentry hashtable counts
  autofs4 - fix lockdep splat in autofs
  vfs: fix d_inode_lookup() dentry ref leak

12 files changed:
fs/autofs4/expire.c
fs/compat.c
fs/dcache.c
fs/inode.c
fs/namei.c
fs/ocfs2/namei.c
fs/quota/quota.c
fs/super.c
include/linux/fs.h
kernel/pid.c
mm/page_alloc.c
net/ipv4/tcp.c

index 450f529a4eaeb6e6d48bd147548a2ad3fb72f961..1feb68ecef9509dd88a4323f3193845af6a84e15 100644 (file)
@@ -124,6 +124,7 @@ start:
        /* Negative dentry - try next */
        if (!simple_positive(q)) {
                spin_unlock(&p->d_lock);
+               lock_set_subclass(&q->d_lock.dep_map, 0, _RET_IP_);
                p = q;
                goto again;
        }
@@ -186,6 +187,7 @@ again:
        /* Negative dentry - try next */
        if (!simple_positive(ret)) {
                spin_unlock(&p->d_lock);
+               lock_set_subclass(&ret->d_lock.dep_map, 0, _RET_IP_);
                p = ret;
                goto again;
        }
index fa9d721ecfee57f8f3b4c2f3b37f2b4e52182ffc..07880bae28a9fa2128eb5df60c6193c39e099fb8 100644 (file)
@@ -131,41 +131,35 @@ asmlinkage long compat_sys_utimes(const char __user *filename, struct compat_tim
 
 static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
 {
-       compat_ino_t ino = stat->ino;
-       typeof(ubuf->st_uid) uid = 0;
-       typeof(ubuf->st_gid) gid = 0;
-       int err;
+       struct compat_stat tmp;
 
-       SET_UID(uid, stat->uid);
-       SET_GID(gid, stat->gid);
+       if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
+               return -EOVERFLOW;
 
-       if ((u64) stat->size > MAX_NON_LFS ||
-           !old_valid_dev(stat->dev) ||
-           !old_valid_dev(stat->rdev))
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.st_dev = old_encode_dev(stat->dev);
+       tmp.st_ino = stat->ino;
+       if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
                return -EOVERFLOW;
-       if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+       tmp.st_mode = stat->mode;
+       tmp.st_nlink = stat->nlink;
+       if (tmp.st_nlink != stat->nlink)
                return -EOVERFLOW;
-
-       if (clear_user(ubuf, sizeof(*ubuf)))
-               return -EFAULT;
-
-       err  = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
-       err |= __put_user(ino, &ubuf->st_ino);
-       err |= __put_user(stat->mode, &ubuf->st_mode);
-       err |= __put_user(stat->nlink, &ubuf->st_nlink);
-       err |= __put_user(uid, &ubuf->st_uid);
-       err |= __put_user(gid, &ubuf->st_gid);
-       err |= __put_user(old_encode_dev(stat->rdev), &ubuf->st_rdev);
-       err |= __put_user(stat->size, &ubuf->st_size);
-       err |= __put_user(stat->atime.tv_sec, &ubuf->st_atime);
-       err |= __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec);
-       err |= __put_user(stat->mtime.tv_sec, &ubuf->st_mtime);
-       err |= __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec);
-       err |= __put_user(stat->ctime.tv_sec, &ubuf->st_ctime);
-       err |= __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec);
-       err |= __put_user(stat->blksize, &ubuf->st_blksize);
-       err |= __put_user(stat->blocks, &ubuf->st_blocks);
-       return err;
+       SET_UID(tmp.st_uid, stat->uid);
+       SET_GID(tmp.st_gid, stat->gid);
+       tmp.st_rdev = old_encode_dev(stat->rdev);
+       if ((u64) stat->size > MAX_NON_LFS)
+               return -EOVERFLOW;
+       tmp.st_size = stat->size;
+       tmp.st_atime = stat->atime.tv_sec;
+       tmp.st_atime_nsec = stat->atime.tv_nsec;
+       tmp.st_mtime = stat->mtime.tv_sec;
+       tmp.st_mtime_nsec = stat->mtime.tv_nsec;
+       tmp.st_ctime = stat->ctime.tv_sec;
+       tmp.st_ctime_nsec = stat->ctime.tv_nsec;
+       tmp.st_blocks = stat->blocks;
+       tmp.st_blksize = stat->blksize;
+       return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
 asmlinkage long compat_sys_newstat(const char __user * filename,
index 16a53cc2cc02e079554742bfcd95c1f92d3608d4..fe19ac13f75f5c4e65ed1afaecd1c5d1ae34ffb6 100644 (file)
@@ -2968,7 +2968,7 @@ __setup("dhash_entries=", set_dhash_entries);
 
 static void __init dcache_init_early(void)
 {
-       int loop;
+       unsigned int loop;
 
        /* If hashes are distributed across NUMA nodes, defer
         * hash allocation until vmalloc space is available.
@@ -2986,13 +2986,13 @@ static void __init dcache_init_early(void)
                                        &d_hash_mask,
                                        0);
 
-       for (loop = 0; loop < (1 << d_hash_shift); loop++)
+       for (loop = 0; loop < (1U << d_hash_shift); loop++)
                INIT_HLIST_BL_HEAD(dentry_hashtable + loop);
 }
 
 static void __init dcache_init(void)
 {
-       int loop;
+       unsigned int loop;
 
        /* 
         * A constructor could be added for stable state like the lists,
@@ -3016,7 +3016,7 @@ static void __init dcache_init(void)
                                        &d_hash_mask,
                                        0);
 
-       for (loop = 0; loop < (1 << d_hash_shift); loop++)
+       for (loop = 0; loop < (1U << d_hash_shift); loop++)
                INIT_HLIST_BL_HEAD(dentry_hashtable + loop);
 }
 
index fb10d86ffad70f8c4ded56ff664470d71f06dc48..d3ebdbe723d0d252358d23a75674d184e639dcb0 100644 (file)
@@ -1651,7 +1651,7 @@ __setup("ihash_entries=", set_ihash_entries);
  */
 void __init inode_init_early(void)
 {
-       int loop;
+       unsigned int loop;
 
        /* If hashes are distributed across NUMA nodes, defer
         * hash allocation until vmalloc space is available.
@@ -1669,13 +1669,13 @@ void __init inode_init_early(void)
                                        &i_hash_mask,
                                        0);
 
-       for (loop = 0; loop < (1 << i_hash_shift); loop++)
+       for (loop = 0; loop < (1U << i_hash_shift); loop++)
                INIT_HLIST_HEAD(&inode_hashtable[loop]);
 }
 
 void __init inode_init(void)
 {
-       int loop;
+       unsigned int loop;
 
        /* inode slab cache */
        inode_cachep = kmem_cache_create("inode_cache",
@@ -1699,7 +1699,7 @@ void __init inode_init(void)
                                        &i_hash_mask,
                                        0);
 
-       for (loop = 0; loop < (1 << i_hash_shift); loop++)
+       for (loop = 0; loop < (1U << i_hash_shift); loop++)
                INIT_HLIST_HEAD(&inode_hashtable[loop]);
 }
 
index 208c6aa4a989dade864a0ca6fcd3bd4b21ba8252..a780ea515c47988623fc4954b734562182ed24c5 100644 (file)
@@ -1095,8 +1095,10 @@ static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentr
        struct dentry *old;
 
        /* Don't create child dentry for a dead directory. */
-       if (unlikely(IS_DEADDIR(inode)))
+       if (unlikely(IS_DEADDIR(inode))) {
+               dput(dentry);
                return ERR_PTR(-ENOENT);
+       }
 
        old = inode->i_op->lookup(inode, dentry, nd);
        if (unlikely(old)) {
index be244692550db3e18cf05987ff577717e1f33173..a9856e3eaaf09753b4921d56ccdfb172db5cad7b 100644 (file)
@@ -1053,7 +1053,7 @@ static int ocfs2_rename(struct inode *old_dir,
        handle_t *handle = NULL;
        struct buffer_head *old_dir_bh = NULL;
        struct buffer_head *new_dir_bh = NULL;
-       nlink_t old_dir_nlink = old_dir->i_nlink;
+       u32 old_dir_nlink = old_dir->i_nlink;
        struct ocfs2_dinode *old_di;
        struct ocfs2_dir_lookup_result old_inode_dot_dot_res = { NULL, };
        struct ocfs2_dir_lookup_result target_lookup_res = { NULL, };
index 7898cd688a0073b8caf6c193fc3deb1dc8722f5f..fc2c4388d1262a1771d27acb7c55507369cf0dba 100644 (file)
@@ -292,11 +292,26 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
        }
 }
 
+/* Return 1 if 'cmd' will block on frozen filesystem */
+static int quotactl_cmd_write(int cmd)
+{
+       switch (cmd) {
+       case Q_GETFMT:
+       case Q_GETINFO:
+       case Q_SYNC:
+       case Q_XGETQSTAT:
+       case Q_XGETQUOTA:
+       case Q_XQUOTASYNC:
+               return 0;
+       }
+       return 1;
+}
+
 /*
  * look up a superblock on which quota ops will be performed
  * - use the name of a block device to find the superblock thereon
  */
-static struct super_block *quotactl_block(const char __user *special)
+static struct super_block *quotactl_block(const char __user *special, int cmd)
 {
 #ifdef CONFIG_BLOCK
        struct block_device *bdev;
@@ -309,7 +324,10 @@ static struct super_block *quotactl_block(const char __user *special)
        putname(tmp);
        if (IS_ERR(bdev))
                return ERR_CAST(bdev);
-       sb = get_super(bdev);
+       if (quotactl_cmd_write(cmd))
+               sb = get_super_thawed(bdev);
+       else
+               sb = get_super(bdev);
        bdput(bdev);
        if (!sb)
                return ERR_PTR(-ENODEV);
@@ -361,7 +379,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
                        pathp = &path;
        }
 
-       sb = quotactl_block(special);
+       sb = quotactl_block(special, cmds);
        if (IS_ERR(sb)) {
                ret = PTR_ERR(sb);
                goto out;
index 6015c02296b7ad2adba75c7946b8fb4762a62265..6277ec6cb60a65e71b2c590260c67a057a1748ca 100644 (file)
@@ -633,6 +633,28 @@ rescan:
 
 EXPORT_SYMBOL(get_super);
 
+/**
+ *     get_super_thawed - get thawed superblock of a device
+ *     @bdev: device to get the superblock for
+ *
+ *     Scans the superblock list and finds the superblock of the file system
+ *     mounted on the device. The superblock is returned once it is thawed
+ *     (or immediately if it was not frozen). %NULL is returned if no match
+ *     is found.
+ */
+struct super_block *get_super_thawed(struct block_device *bdev)
+{
+       while (1) {
+               struct super_block *s = get_super(bdev);
+               if (!s || s->s_frozen == SB_UNFROZEN)
+                       return s;
+               up_read(&s->s_umount);
+               vfs_check_frozen(s, SB_FREEZE_WRITE);
+               put_super(s);
+       }
+}
+EXPORT_SYMBOL(get_super_thawed);
+
 /**
  * get_active_super - get an active reference to the superblock of a device
  * @bdev: device to get the superblock for
index 386da09f229dfad8ff8ef5600c8045f221ae862f..69cd5bb640f5f6f0e4dd13431c34c6f8c760f42b 100644 (file)
@@ -2496,6 +2496,7 @@ extern void get_filesystem(struct file_system_type *fs);
 extern void put_filesystem(struct file_system_type *fs);
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(struct block_device *);
+extern struct super_block *get_super_thawed(struct block_device *);
 extern struct super_block *get_active_super(struct block_device *bdev);
 extern void drop_super(struct super_block *sb);
 extern void iterate_supers(void (*)(struct super_block *, void *), void *);
index ce8e00deaccb38452188436438dc942313bd6c44..9f08dfabaf13af1f79a8ae4c5bb87a4434736d18 100644 (file)
@@ -543,12 +543,12 @@ struct pid *find_ge_pid(int nr, struct pid_namespace *ns)
  */
 void __init pidhash_init(void)
 {
-       int i, pidhash_size;
+       unsigned int i, pidhash_size;
 
        pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18,
                                           HASH_EARLY | HASH_SMALL,
                                           &pidhash_shift, NULL, 4096);
-       pidhash_size = 1 << pidhash_shift;
+       pidhash_size = 1U << pidhash_shift;
 
        for (i = 0; i < pidhash_size; i++)
                INIT_HLIST_HEAD(&pid_hash[i]);
index d2186ecb36f7cdfd5fdc75da4bbd10ef798bcbba..a13ded1938f0bacd90a438d983e3d301a649bfe9 100644 (file)
@@ -5236,6 +5236,7 @@ void *__init alloc_large_system_hash(const char *tablename,
                max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4;
                do_div(max, bucketsize);
        }
+       max = min(max, 0x80000000ULL);
 
        if (numentries > max)
                numentries = max;
index 37755ccc0e96d8da1b36e0c43e695b0f0a6431e4..22ef5f9fd2ff2e92dc4955dc9a2ac450d8a435fa 100644 (file)
@@ -3240,7 +3240,8 @@ void __init tcp_init(void)
 {
        struct sk_buff *skb = NULL;
        unsigned long limit;
-       int i, max_share, cnt;
+       int max_share, cnt;
+       unsigned int i;
        unsigned long jiffy = jiffies;
 
        BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
@@ -3283,7 +3284,7 @@ void __init tcp_init(void)
                                        &tcp_hashinfo.bhash_size,
                                        NULL,
                                        64 * 1024);
-       tcp_hashinfo.bhash_size = 1 << tcp_hashinfo.bhash_size;
+       tcp_hashinfo.bhash_size = 1U << tcp_hashinfo.bhash_size;
        for (i = 0; i < tcp_hashinfo.bhash_size; i++) {
                spin_lock_init(&tcp_hashinfo.bhash[i].lock);
                INIT_HLIST_HEAD(&tcp_hashinfo.bhash[i].chain);