| From: Al Viro <viro@zeniv.linux.org.uk> |
| Date: Thu, 4 Sep 2014 09:38:11 -0400 |
| Subject: udf: fix the udf_iget() vs. udf_new_inode() races |
| |
| commit b231509616feb911c2a7a8814d58c0014ef5b17f upstream. |
| |
| Currently udf_iget() (triggered by NFS) can race with udf_new_inode() |
| leading to two inode structures with the same inode number: |
| |
| nfsd: iget_locked() creates inode |
| nfsd: try to read from disk, block on that. |
| udf_new_inode(): allocate inode with that inumber |
| udf_new_inode(): insert it into icache, set it up and dirty |
| udf_write_inode(): write inode into buffer cache |
| nfsd: get CPU again, look into buffer cache, see nice and sane on-disk |
| inode, set the in-core inode from it |
| |
| Fix the problem by putting inode into icache in locked state (I_NEW set) |
| and unlocking it only after it's fully set up. |
| |
| Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| fs/udf/ialloc.c | 7 ++++++- |
| fs/udf/namei.c | 7 +++++++ |
| 2 files changed, 13 insertions(+), 1 deletion(-) |
| |
| --- a/fs/udf/ialloc.c |
| +++ b/fs/udf/ialloc.c |
| @@ -123,7 +123,12 @@ struct inode *udf_new_inode(struct inode |
| iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; |
| inode->i_mtime = inode->i_atime = inode->i_ctime = |
| iinfo->i_crtime = current_fs_time(inode->i_sb); |
| - insert_inode_hash(inode); |
| + if (unlikely(insert_inode_locked(inode) < 0)) { |
| + make_bad_inode(inode); |
| + iput(inode); |
| + *err = -EIO; |
| + return NULL; |
| + } |
| mark_inode_dirty(inode); |
| |
| *err = 0; |
| --- a/fs/udf/namei.c |
| +++ b/fs/udf/namei.c |
| @@ -562,6 +562,7 @@ static int udf_add_nondir(struct dentry |
| fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err); |
| if (unlikely(!fi)) { |
| inode_dec_link_count(inode); |
| + unlock_new_inode(inode); |
| iput(inode); |
| return err; |
| } |
| @@ -575,6 +576,7 @@ static int udf_add_nondir(struct dentry |
| if (fibh.sbh != fibh.ebh) |
| brelse(fibh.ebh); |
| brelse(fibh.sbh); |
| + unlock_new_inode(inode); |
| d_instantiate(dentry, inode); |
| |
| return 0; |
| @@ -622,6 +624,7 @@ static int udf_tmpfile(struct inode *dir |
| mark_inode_dirty(inode); |
| |
| d_tmpfile(dentry, inode); |
| + unlock_new_inode(inode); |
| return 0; |
| } |
| |
| @@ -663,6 +666,7 @@ static int udf_mkdir(struct inode *dir, |
| fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err); |
| if (!fi) { |
| inode_dec_link_count(inode); |
| + unlock_new_inode(inode); |
| iput(inode); |
| goto out; |
| } |
| @@ -681,6 +685,7 @@ static int udf_mkdir(struct inode *dir, |
| if (!fi) { |
| clear_nlink(inode); |
| mark_inode_dirty(inode); |
| + unlock_new_inode(inode); |
| iput(inode); |
| goto out; |
| } |
| @@ -692,6 +697,7 @@ static int udf_mkdir(struct inode *dir, |
| udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); |
| inc_nlink(dir); |
| mark_inode_dirty(dir); |
| + unlock_new_inode(inode); |
| d_instantiate(dentry, inode); |
| if (fibh.sbh != fibh.ebh) |
| brelse(fibh.ebh); |
| @@ -999,6 +1005,7 @@ out: |
| out_no_entry: |
| up_write(&iinfo->i_data_sem); |
| inode_dec_link_count(inode); |
| + unlock_new_inode(inode); |
| iput(inode); |
| goto out; |
| } |