aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-13 18:56:27 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-13 18:56:27 -0500
commit2821fe6b00a1e902fd399bb4b7e40bc3041f4d44 (patch)
treeec95a7f7e79c26abd48c82c238cdec5ac8a74d60
parentf47671e2d861a2093179cd64dda22016664b2015 (diff)
parent441a9d0e1e827e6433e3487145fbb0c5513301e2 (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.c7
-rw-r--r--fs/aio.c4
-rw-r--r--fs/dcache.c13
-rw-r--r--fs/locks.c1
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;
468bail: 468bail:
@@ -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
511bail: 514bail:
512 mutex_unlock(&root->d_inode->i_mutex); 515 mutex_unlock(&root->d_inode->i_mutex);
diff --git a/fs/aio.c b/fs/aio.c
index 1f602d9be4c5..823efcbb6ccd 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -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,
2924restart_mnt: 2924restart_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();
2927restart: 2928restart:
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 }