Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/vfs

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
  • Loading branch information
torvalds committed Feb 21, 2012
2 parents 39e255d + 847c9db commit 8ebbfb4
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 48 deletions.
2 changes: 2 additions & 0 deletions fs/autofs4/expire.c
Expand Up @@ -124,6 +124,7 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev,
/* Negative dentry - try next */ /* Negative dentry - try next */
if (!simple_positive(q)) { if (!simple_positive(q)) {
spin_unlock(&p->d_lock); spin_unlock(&p->d_lock);
lock_set_subclass(&q->d_lock.dep_map, 0, _RET_IP_);
p = q; p = q;
goto again; goto again;
} }
Expand Down Expand Up @@ -186,6 +187,7 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev,
/* Negative dentry - try next */ /* Negative dentry - try next */
if (!simple_positive(ret)) { if (!simple_positive(ret)) {
spin_unlock(&p->d_lock); spin_unlock(&p->d_lock);
lock_set_subclass(&ret->d_lock.dep_map, 0, _RET_IP_);
p = ret; p = ret;
goto again; goto again;
} }
Expand Down
56 changes: 25 additions & 31 deletions fs/compat.c
Expand Up @@ -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) static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
{ {
compat_ino_t ino = stat->ino; struct compat_stat tmp;
typeof(ubuf->st_uid) uid = 0;
typeof(ubuf->st_gid) gid = 0;
int err;


SET_UID(uid, stat->uid); if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
SET_GID(gid, stat->gid); return -EOVERFLOW;


if ((u64) stat->size > MAX_NON_LFS || memset(&tmp, 0, sizeof(tmp));
!old_valid_dev(stat->dev) || tmp.st_dev = old_encode_dev(stat->dev);
!old_valid_dev(stat->rdev)) tmp.st_ino = stat->ino;
if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
return -EOVERFLOW; 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; return -EOVERFLOW;

SET_UID(tmp.st_uid, stat->uid);
if (clear_user(ubuf, sizeof(*ubuf))) SET_GID(tmp.st_gid, stat->gid);
return -EFAULT; tmp.st_rdev = old_encode_dev(stat->rdev);

if ((u64) stat->size > MAX_NON_LFS)
err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev); return -EOVERFLOW;
err |= __put_user(ino, &ubuf->st_ino); tmp.st_size = stat->size;
err |= __put_user(stat->mode, &ubuf->st_mode); tmp.st_atime = stat->atime.tv_sec;
err |= __put_user(stat->nlink, &ubuf->st_nlink); tmp.st_atime_nsec = stat->atime.tv_nsec;
err |= __put_user(uid, &ubuf->st_uid); tmp.st_mtime = stat->mtime.tv_sec;
err |= __put_user(gid, &ubuf->st_gid); tmp.st_mtime_nsec = stat->mtime.tv_nsec;
err |= __put_user(old_encode_dev(stat->rdev), &ubuf->st_rdev); tmp.st_ctime = stat->ctime.tv_sec;
err |= __put_user(stat->size, &ubuf->st_size); tmp.st_ctime_nsec = stat->ctime.tv_nsec;
err |= __put_user(stat->atime.tv_sec, &ubuf->st_atime); tmp.st_blocks = stat->blocks;
err |= __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec); tmp.st_blksize = stat->blksize;
err |= __put_user(stat->mtime.tv_sec, &ubuf->st_mtime); return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
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;
} }


asmlinkage long compat_sys_newstat(const char __user * filename, asmlinkage long compat_sys_newstat(const char __user * filename,
Expand Down
8 changes: 4 additions & 4 deletions fs/dcache.c
Expand Up @@ -2968,7 +2968,7 @@ __setup("dhash_entries=", set_dhash_entries);


static void __init dcache_init_early(void) static void __init dcache_init_early(void)
{ {
int loop; unsigned int loop;


/* If hashes are distributed across NUMA nodes, defer /* If hashes are distributed across NUMA nodes, defer
* hash allocation until vmalloc space is available. * hash allocation until vmalloc space is available.
Expand All @@ -2986,13 +2986,13 @@ static void __init dcache_init_early(void)
&d_hash_mask, &d_hash_mask,
0); 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); INIT_HLIST_BL_HEAD(dentry_hashtable + loop);
} }


static void __init dcache_init(void) static void __init dcache_init(void)
{ {
int loop; unsigned int loop;


/* /*
* A constructor could be added for stable state like the lists, * A constructor could be added for stable state like the lists,
Expand All @@ -3016,7 +3016,7 @@ static void __init dcache_init(void)
&d_hash_mask, &d_hash_mask,
0); 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); INIT_HLIST_BL_HEAD(dentry_hashtable + loop);
} }


Expand Down
8 changes: 4 additions & 4 deletions fs/inode.c
Expand Up @@ -1651,7 +1651,7 @@ __setup("ihash_entries=", set_ihash_entries);
*/ */
void __init inode_init_early(void) void __init inode_init_early(void)
{ {
int loop; unsigned int loop;


/* If hashes are distributed across NUMA nodes, defer /* If hashes are distributed across NUMA nodes, defer
* hash allocation until vmalloc space is available. * hash allocation until vmalloc space is available.
Expand All @@ -1669,13 +1669,13 @@ void __init inode_init_early(void)
&i_hash_mask, &i_hash_mask,
0); 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]); INIT_HLIST_HEAD(&inode_hashtable[loop]);
} }


void __init inode_init(void) void __init inode_init(void)
{ {
int loop; unsigned int loop;


/* inode slab cache */ /* inode slab cache */
inode_cachep = kmem_cache_create("inode_cache", inode_cachep = kmem_cache_create("inode_cache",
Expand All @@ -1699,7 +1699,7 @@ void __init inode_init(void)
&i_hash_mask, &i_hash_mask,
0); 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]); INIT_HLIST_HEAD(&inode_hashtable[loop]);
} }


Expand Down
4 changes: 3 additions & 1 deletion fs/namei.c
Expand Up @@ -1095,8 +1095,10 @@ static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentr
struct dentry *old; struct dentry *old;


/* Don't create child dentry for a dead directory. */ /* 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); return ERR_PTR(-ENOENT);
}


old = inode->i_op->lookup(inode, dentry, nd); old = inode->i_op->lookup(inode, dentry, nd);
if (unlikely(old)) { if (unlikely(old)) {
Expand Down
2 changes: 1 addition & 1 deletion fs/ocfs2/namei.c
Expand Up @@ -1053,7 +1053,7 @@ static int ocfs2_rename(struct inode *old_dir,
handle_t *handle = NULL; handle_t *handle = NULL;
struct buffer_head *old_dir_bh = NULL; struct buffer_head *old_dir_bh = NULL;
struct buffer_head *new_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_dinode *old_di;
struct ocfs2_dir_lookup_result old_inode_dot_dot_res = { NULL, }; struct ocfs2_dir_lookup_result old_inode_dot_dot_res = { NULL, };
struct ocfs2_dir_lookup_result target_lookup_res = { NULL, }; struct ocfs2_dir_lookup_result target_lookup_res = { NULL, };
Expand Down
24 changes: 21 additions & 3 deletions fs/quota/quota.c
Expand Up @@ -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 * look up a superblock on which quota ops will be performed
* - use the name of a block device to find the superblock thereon * - 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 #ifdef CONFIG_BLOCK
struct block_device *bdev; struct block_device *bdev;
Expand All @@ -309,7 +324,10 @@ static struct super_block *quotactl_block(const char __user *special)
putname(tmp); putname(tmp);
if (IS_ERR(bdev)) if (IS_ERR(bdev))
return ERR_CAST(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); bdput(bdev);
if (!sb) if (!sb)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
Expand Down Expand Up @@ -361,7 +379,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
pathp = &path; pathp = &path;
} }


sb = quotactl_block(special); sb = quotactl_block(special, cmds);
if (IS_ERR(sb)) { if (IS_ERR(sb)) {
ret = PTR_ERR(sb); ret = PTR_ERR(sb);
goto out; goto out;
Expand Down
22 changes: 22 additions & 0 deletions fs/super.c
Expand Up @@ -633,6 +633,28 @@ struct super_block *get_super(struct block_device *bdev)


EXPORT_SYMBOL(get_super); 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 * get_active_super - get an active reference to the superblock of a device
* @bdev: device to get the superblock for * @bdev: device to get the superblock for
Expand Down
1 change: 1 addition & 0 deletions include/linux/fs.h
Expand Up @@ -2496,6 +2496,7 @@ extern void get_filesystem(struct file_system_type *fs);
extern void put_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 file_system_type *get_fs_type(const char *name);
extern struct super_block *get_super(struct block_device *); 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 struct super_block *get_active_super(struct block_device *bdev);
extern void drop_super(struct super_block *sb); extern void drop_super(struct super_block *sb);
extern void iterate_supers(void (*)(struct super_block *, void *), void *); extern void iterate_supers(void (*)(struct super_block *, void *), void *);
Expand Down
4 changes: 2 additions & 2 deletions kernel/pid.c
Expand Up @@ -543,12 +543,12 @@ struct pid *find_ge_pid(int nr, struct pid_namespace *ns)
*/ */
void __init pidhash_init(void) 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, pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18,
HASH_EARLY | HASH_SMALL, HASH_EARLY | HASH_SMALL,
&pidhash_shift, NULL, 4096); &pidhash_shift, NULL, 4096);
pidhash_size = 1 << pidhash_shift; pidhash_size = 1U << pidhash_shift;


for (i = 0; i < pidhash_size; i++) for (i = 0; i < pidhash_size; i++)
INIT_HLIST_HEAD(&pid_hash[i]); INIT_HLIST_HEAD(&pid_hash[i]);
Expand Down
1 change: 1 addition & 0 deletions mm/page_alloc.c
Expand Up @@ -5236,6 +5236,7 @@ void *__init alloc_large_system_hash(const char *tablename,
max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4; max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4;
do_div(max, bucketsize); do_div(max, bucketsize);
} }
max = min(max, 0x80000000ULL);


if (numentries > max) if (numentries > max)
numentries = max; numentries = max;
Expand Down
5 changes: 3 additions & 2 deletions net/ipv4/tcp.c
Expand Up @@ -3240,7 +3240,8 @@ void __init tcp_init(void)
{ {
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
unsigned long limit; unsigned long limit;
int i, max_share, cnt; int max_share, cnt;
unsigned int i;
unsigned long jiffy = jiffies; unsigned long jiffy = jiffies;


BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb)); BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
Expand Down Expand Up @@ -3283,7 +3284,7 @@ void __init tcp_init(void)
&tcp_hashinfo.bhash_size, &tcp_hashinfo.bhash_size,
NULL, NULL,
64 * 1024); 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++) { for (i = 0; i < tcp_hashinfo.bhash_size; i++) {
spin_lock_init(&tcp_hashinfo.bhash[i].lock); spin_lock_init(&tcp_hashinfo.bhash[i].lock);
INIT_HLIST_HEAD(&tcp_hashinfo.bhash[i].chain); INIT_HLIST_HEAD(&tcp_hashinfo.bhash[i].chain);
Expand Down

0 comments on commit 8ebbfb4

Please sign in to comment.