diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-13 18:56:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-13 18:56:27 -0500 |
commit | 2821fe6b00a1e902fd399bb4b7e40bc3041f4d44 (patch) | |
tree | ec95a7f7e79c26abd48c82c238cdec5ac8a74d60 | |
parent | f47671e2d861a2093179cd64dda22016664b2015 (diff) | |
parent | 441a9d0e1e827e6433e3487145fbb0c5513301e2 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull VFS fixes from Al Viro:
"Several fixes, mostly for regressions in the last pile. Howeover,
prepend_path() forgetting to reininitalize dentry/vfsmount is in 3.12
as well and qib_fs had been leaking all along..."
The unpaired RCU lock issue was also independently reported by Dave
Jones with his fuzzer tool..
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
qib_fs: fix (some) dcache abuses
prepend_path() needs to reinitialize dentry/vfsmount/mnt on restarts
fix unpaired rcu lock in prepend_path()
locks: missing unlock on error in generic_add_lease()
aio: checking for NULL instead of IS_ERR
-rw-r--r-- | drivers/infiniband/hw/qib/qib_fs.c | 7 | ||||
-rw-r--r-- | fs/aio.c | 4 | ||||
-rw-r--r-- | fs/dcache.c | 13 | ||||
-rw-r--r-- | fs/locks.c | 1 |
4 files changed, 18 insertions, 7 deletions
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index f247fc6e6182..c61e2a92b3c1 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c | |||
@@ -456,13 +456,13 @@ static int remove_file(struct dentry *parent, char *name) | |||
456 | 456 | ||
457 | spin_lock(&tmp->d_lock); | 457 | spin_lock(&tmp->d_lock); |
458 | if (!(d_unhashed(tmp) && tmp->d_inode)) { | 458 | if (!(d_unhashed(tmp) && tmp->d_inode)) { |
459 | dget_dlock(tmp); | ||
460 | __d_drop(tmp); | 459 | __d_drop(tmp); |
461 | spin_unlock(&tmp->d_lock); | 460 | spin_unlock(&tmp->d_lock); |
462 | simple_unlink(parent->d_inode, tmp); | 461 | simple_unlink(parent->d_inode, tmp); |
463 | } else { | 462 | } else { |
464 | spin_unlock(&tmp->d_lock); | 463 | spin_unlock(&tmp->d_lock); |
465 | } | 464 | } |
465 | dput(tmp); | ||
466 | 466 | ||
467 | ret = 0; | 467 | ret = 0; |
468 | bail: | 468 | bail: |
@@ -491,6 +491,7 @@ static int remove_device_files(struct super_block *sb, | |||
491 | goto bail; | 491 | goto bail; |
492 | } | 492 | } |
493 | 493 | ||
494 | mutex_lock(&dir->d_inode->i_mutex); | ||
494 | remove_file(dir, "counters"); | 495 | remove_file(dir, "counters"); |
495 | remove_file(dir, "counter_names"); | 496 | remove_file(dir, "counter_names"); |
496 | remove_file(dir, "portcounter_names"); | 497 | remove_file(dir, "portcounter_names"); |
@@ -505,8 +506,10 @@ static int remove_device_files(struct super_block *sb, | |||
505 | } | 506 | } |
506 | } | 507 | } |
507 | remove_file(dir, "flash"); | 508 | remove_file(dir, "flash"); |
508 | d_delete(dir); | 509 | mutex_unlock(&dir->d_inode->i_mutex); |
509 | ret = simple_rmdir(root->d_inode, dir); | 510 | ret = simple_rmdir(root->d_inode, dir); |
511 | d_delete(dir); | ||
512 | dput(dir); | ||
510 | 513 | ||
511 | bail: | 514 | bail: |
512 | mutex_unlock(&root->d_inode->i_mutex); | 515 | mutex_unlock(&root->d_inode->i_mutex); |
@@ -163,8 +163,8 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages) | |||
163 | struct file *file; | 163 | struct file *file; |
164 | struct path path; | 164 | struct path path; |
165 | struct inode *inode = alloc_anon_inode(aio_mnt->mnt_sb); | 165 | struct inode *inode = alloc_anon_inode(aio_mnt->mnt_sb); |
166 | if (!inode) | 166 | if (IS_ERR(inode)) |
167 | return ERR_PTR(-ENOMEM); | 167 | return ERR_CAST(inode); |
168 | 168 | ||
169 | inode->i_mapping->a_ops = &aio_ctx_aops; | 169 | inode->i_mapping->a_ops = &aio_ctx_aops; |
170 | inode->i_mapping->private_data = ctx; | 170 | inode->i_mapping->private_data = ctx; |
diff --git a/fs/dcache.c b/fs/dcache.c index 1f24cd684c51..a9dd384c5e80 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -2912,9 +2912,9 @@ static int prepend_path(const struct path *path, | |||
2912 | const struct path *root, | 2912 | const struct path *root, |
2913 | char **buffer, int *buflen) | 2913 | char **buffer, int *buflen) |
2914 | { | 2914 | { |
2915 | struct dentry *dentry = path->dentry; | 2915 | struct dentry *dentry; |
2916 | struct vfsmount *vfsmnt = path->mnt; | 2916 | struct vfsmount *vfsmnt; |
2917 | struct mount *mnt = real_mount(vfsmnt); | 2917 | struct mount *mnt; |
2918 | int error = 0; | 2918 | int error = 0; |
2919 | unsigned seq, m_seq = 0; | 2919 | unsigned seq, m_seq = 0; |
2920 | char *bptr; | 2920 | char *bptr; |
@@ -2924,10 +2924,14 @@ static int prepend_path(const struct path *path, | |||
2924 | restart_mnt: | 2924 | restart_mnt: |
2925 | read_seqbegin_or_lock(&mount_lock, &m_seq); | 2925 | read_seqbegin_or_lock(&mount_lock, &m_seq); |
2926 | seq = 0; | 2926 | seq = 0; |
2927 | rcu_read_lock(); | ||
2927 | restart: | 2928 | restart: |
2928 | bptr = *buffer; | 2929 | bptr = *buffer; |
2929 | blen = *buflen; | 2930 | blen = *buflen; |
2930 | error = 0; | 2931 | error = 0; |
2932 | dentry = path->dentry; | ||
2933 | vfsmnt = path->mnt; | ||
2934 | mnt = real_mount(vfsmnt); | ||
2931 | read_seqbegin_or_lock(&rename_lock, &seq); | 2935 | read_seqbegin_or_lock(&rename_lock, &seq); |
2932 | while (dentry != root->dentry || vfsmnt != root->mnt) { | 2936 | while (dentry != root->dentry || vfsmnt != root->mnt) { |
2933 | struct dentry * parent; | 2937 | struct dentry * parent; |
@@ -2971,6 +2975,9 @@ restart: | |||
2971 | goto restart; | 2975 | goto restart; |
2972 | } | 2976 | } |
2973 | done_seqretry(&rename_lock, seq); | 2977 | done_seqretry(&rename_lock, seq); |
2978 | |||
2979 | if (!(m_seq & 1)) | ||
2980 | rcu_read_unlock(); | ||
2974 | if (need_seqretry(&mount_lock, m_seq)) { | 2981 | if (need_seqretry(&mount_lock, m_seq)) { |
2975 | m_seq = 1; | 2982 | m_seq = 1; |
2976 | goto restart_mnt; | 2983 | goto restart_mnt; |
diff --git a/fs/locks.c b/fs/locks.c index f99d52bdd05a..92a0f0a52b06 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1494,6 +1494,7 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp | |||
1494 | 1494 | ||
1495 | if (is_deleg && arg == F_WRLCK) { | 1495 | if (is_deleg && arg == F_WRLCK) { |
1496 | /* Write delegations are not currently supported: */ | 1496 | /* Write delegations are not currently supported: */ |
1497 | mutex_unlock(&inode->i_mutex); | ||
1497 | WARN_ON_ONCE(1); | 1498 | WARN_ON_ONCE(1); |
1498 | return -EINVAL; | 1499 | return -EINVAL; |
1499 | } | 1500 | } |