diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-09-04 09:38:11 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2014-09-04 15:37:41 -0400 |
commit | b231509616feb911c2a7a8814d58c0014ef5b17f (patch) | |
tree | da9d231b09ee58637fb671310291432929c9db56 | |
parent | d2be51cb34dc501791f3b8c01a99a3f2064bd8d1 (diff) |
udf: fix the udf_iget() vs. udf_new_inode() races
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>
-rw-r--r-- | fs/udf/ialloc.c | 7 | ||||
-rw-r--r-- | fs/udf/namei.c | 7 |
2 files changed, 13 insertions, 1 deletions
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index 647370d70175..598f33bdcd26 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c | |||
@@ -124,7 +124,12 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err) | |||
124 | iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; | 124 | iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; |
125 | inode->i_mtime = inode->i_atime = inode->i_ctime = | 125 | inode->i_mtime = inode->i_atime = inode->i_ctime = |
126 | iinfo->i_crtime = current_fs_time(inode->i_sb); | 126 | iinfo->i_crtime = current_fs_time(inode->i_sb); |
127 | insert_inode_hash(inode); | 127 | if (unlikely(insert_inode_locked(inode) < 0)) { |
128 | make_bad_inode(inode); | ||
129 | iput(inode); | ||
130 | *err = -EIO; | ||
131 | return NULL; | ||
132 | } | ||
128 | mark_inode_dirty(inode); | 133 | mark_inode_dirty(inode); |
129 | 134 | ||
130 | *err = 0; | 135 | *err = 0; |
diff --git a/fs/udf/namei.c b/fs/udf/namei.c index abec86466735..d106fdd1bef7 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c | |||
@@ -559,6 +559,7 @@ static int udf_add_nondir(struct dentry *dentry, struct inode *inode) | |||
559 | fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err); | 559 | fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err); |
560 | if (unlikely(!fi)) { | 560 | if (unlikely(!fi)) { |
561 | inode_dec_link_count(inode); | 561 | inode_dec_link_count(inode); |
562 | unlock_new_inode(inode); | ||
562 | iput(inode); | 563 | iput(inode); |
563 | return err; | 564 | return err; |
564 | } | 565 | } |
@@ -572,6 +573,7 @@ static int udf_add_nondir(struct dentry *dentry, struct inode *inode) | |||
572 | if (fibh.sbh != fibh.ebh) | 573 | if (fibh.sbh != fibh.ebh) |
573 | brelse(fibh.ebh); | 574 | brelse(fibh.ebh); |
574 | brelse(fibh.sbh); | 575 | brelse(fibh.sbh); |
576 | unlock_new_inode(inode); | ||
575 | d_instantiate(dentry, inode); | 577 | d_instantiate(dentry, inode); |
576 | 578 | ||
577 | return 0; | 579 | return 0; |
@@ -619,6 +621,7 @@ static int udf_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
619 | mark_inode_dirty(inode); | 621 | mark_inode_dirty(inode); |
620 | 622 | ||
621 | d_tmpfile(dentry, inode); | 623 | d_tmpfile(dentry, inode); |
624 | unlock_new_inode(inode); | ||
622 | return 0; | 625 | return 0; |
623 | } | 626 | } |
624 | 627 | ||
@@ -660,6 +663,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
660 | fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err); | 663 | fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err); |
661 | if (!fi) { | 664 | if (!fi) { |
662 | inode_dec_link_count(inode); | 665 | inode_dec_link_count(inode); |
666 | unlock_new_inode(inode); | ||
663 | iput(inode); | 667 | iput(inode); |
664 | goto out; | 668 | goto out; |
665 | } | 669 | } |
@@ -678,6 +682,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
678 | if (!fi) { | 682 | if (!fi) { |
679 | clear_nlink(inode); | 683 | clear_nlink(inode); |
680 | mark_inode_dirty(inode); | 684 | mark_inode_dirty(inode); |
685 | unlock_new_inode(inode); | ||
681 | iput(inode); | 686 | iput(inode); |
682 | goto out; | 687 | goto out; |
683 | } | 688 | } |
@@ -689,6 +694,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
689 | udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); | 694 | udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); |
690 | inc_nlink(dir); | 695 | inc_nlink(dir); |
691 | mark_inode_dirty(dir); | 696 | mark_inode_dirty(dir); |
697 | unlock_new_inode(inode); | ||
692 | d_instantiate(dentry, inode); | 698 | d_instantiate(dentry, inode); |
693 | if (fibh.sbh != fibh.ebh) | 699 | if (fibh.sbh != fibh.ebh) |
694 | brelse(fibh.ebh); | 700 | brelse(fibh.ebh); |
@@ -996,6 +1002,7 @@ out: | |||
996 | out_no_entry: | 1002 | out_no_entry: |
997 | up_write(&iinfo->i_data_sem); | 1003 | up_write(&iinfo->i_data_sem); |
998 | inode_dec_link_count(inode); | 1004 | inode_dec_link_count(inode); |
1005 | unlock_new_inode(inode); | ||
999 | iput(inode); | 1006 | iput(inode); |
1000 | goto out; | 1007 | goto out; |
1001 | } | 1008 | } |