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 | } |
