diff options
Diffstat (limited to 'fs/ext3/namei.c')
-rw-r--r-- | fs/ext3/namei.c | 140 |
1 files changed, 81 insertions, 59 deletions
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 2b35ddb70d65..b27ba71810ec 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
@@ -858,6 +858,7 @@ static struct buffer_head *ext3_find_entry(struct inode *dir, | |||
858 | struct buffer_head * bh_use[NAMEI_RA_SIZE]; | 858 | struct buffer_head * bh_use[NAMEI_RA_SIZE]; |
859 | struct buffer_head * bh, *ret = NULL; | 859 | struct buffer_head * bh, *ret = NULL; |
860 | unsigned long start, block, b; | 860 | unsigned long start, block, b; |
861 | const u8 *name = entry->name; | ||
861 | int ra_max = 0; /* Number of bh's in the readahead | 862 | int ra_max = 0; /* Number of bh's in the readahead |
862 | buffer, bh_use[] */ | 863 | buffer, bh_use[] */ |
863 | int ra_ptr = 0; /* Current index into readahead | 864 | int ra_ptr = 0; /* Current index into readahead |
@@ -871,6 +872,16 @@ static struct buffer_head *ext3_find_entry(struct inode *dir, | |||
871 | namelen = entry->len; | 872 | namelen = entry->len; |
872 | if (namelen > EXT3_NAME_LEN) | 873 | if (namelen > EXT3_NAME_LEN) |
873 | return NULL; | 874 | return NULL; |
875 | if ((namelen <= 2) && (name[0] == '.') && | ||
876 | (name[1] == '.' || name[1] == 0)) { | ||
877 | /* | ||
878 | * "." or ".." will only be in the first block | ||
879 | * NFS may look up ".."; "." should be handled by the VFS | ||
880 | */ | ||
881 | block = start = 0; | ||
882 | nblocks = 1; | ||
883 | goto restart; | ||
884 | } | ||
874 | if (is_dx(dir)) { | 885 | if (is_dx(dir)) { |
875 | bh = ext3_dx_find_entry(dir, entry, res_dir, &err); | 886 | bh = ext3_dx_find_entry(dir, entry, res_dir, &err); |
876 | /* | 887 | /* |
@@ -961,55 +972,35 @@ static struct buffer_head * ext3_dx_find_entry(struct inode *dir, | |||
961 | struct qstr *entry, struct ext3_dir_entry_2 **res_dir, | 972 | struct qstr *entry, struct ext3_dir_entry_2 **res_dir, |
962 | int *err) | 973 | int *err) |
963 | { | 974 | { |
964 | struct super_block * sb; | 975 | struct super_block *sb = dir->i_sb; |
965 | struct dx_hash_info hinfo; | 976 | struct dx_hash_info hinfo; |
966 | u32 hash; | ||
967 | struct dx_frame frames[2], *frame; | 977 | struct dx_frame frames[2], *frame; |
968 | struct ext3_dir_entry_2 *de, *top; | ||
969 | struct buffer_head *bh; | 978 | struct buffer_head *bh; |
970 | unsigned long block; | 979 | unsigned long block; |
971 | int retval; | 980 | int retval; |
972 | int namelen = entry->len; | ||
973 | const u8 *name = entry->name; | ||
974 | 981 | ||
975 | sb = dir->i_sb; | 982 | if (!(frame = dx_probe(entry, dir, &hinfo, frames, err))) |
976 | /* NFS may look up ".." - look at dx_root directory block */ | 983 | return NULL; |
977 | if (namelen > 2 || name[0] != '.'|| (namelen == 2 && name[1] != '.')) { | ||
978 | if (!(frame = dx_probe(entry, dir, &hinfo, frames, err))) | ||
979 | return NULL; | ||
980 | } else { | ||
981 | frame = frames; | ||
982 | frame->bh = NULL; /* for dx_release() */ | ||
983 | frame->at = (struct dx_entry *)frames; /* hack for zero entry*/ | ||
984 | dx_set_block(frame->at, 0); /* dx_root block is 0 */ | ||
985 | } | ||
986 | hash = hinfo.hash; | ||
987 | do { | 984 | do { |
988 | block = dx_get_block(frame->at); | 985 | block = dx_get_block(frame->at); |
989 | if (!(bh = ext3_bread (NULL,dir, block, 0, err))) | 986 | if (!(bh = ext3_bread (NULL,dir, block, 0, err))) |
990 | goto errout; | 987 | goto errout; |
991 | de = (struct ext3_dir_entry_2 *) bh->b_data; | ||
992 | top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_blocksize - | ||
993 | EXT3_DIR_REC_LEN(0)); | ||
994 | for (; de < top; de = ext3_next_entry(de)) { | ||
995 | int off = (block << EXT3_BLOCK_SIZE_BITS(sb)) | ||
996 | + ((char *) de - bh->b_data); | ||
997 | |||
998 | if (!ext3_check_dir_entry(__func__, dir, de, bh, off)) { | ||
999 | brelse(bh); | ||
1000 | *err = ERR_BAD_DX_DIR; | ||
1001 | goto errout; | ||
1002 | } | ||
1003 | 988 | ||
1004 | if (ext3_match(namelen, name, de)) { | 989 | retval = search_dirblock(bh, dir, entry, |
1005 | *res_dir = de; | 990 | block << EXT3_BLOCK_SIZE_BITS(sb), |
1006 | dx_release(frames); | 991 | res_dir); |
1007 | return bh; | 992 | if (retval == 1) { |
1008 | } | 993 | dx_release(frames); |
994 | return bh; | ||
1009 | } | 995 | } |
1010 | brelse (bh); | 996 | brelse(bh); |
997 | if (retval == -1) { | ||
998 | *err = ERR_BAD_DX_DIR; | ||
999 | goto errout; | ||
1000 | } | ||
1001 | |||
1011 | /* Check to see if we should continue to search */ | 1002 | /* Check to see if we should continue to search */ |
1012 | retval = ext3_htree_next_block(dir, hash, frame, | 1003 | retval = ext3_htree_next_block(dir, hinfo.hash, frame, |
1013 | frames, NULL); | 1004 | frames, NULL); |
1014 | if (retval < 0) { | 1005 | if (retval < 0) { |
1015 | ext3_warning(sb, __func__, | 1006 | ext3_warning(sb, __func__, |
@@ -1047,7 +1038,7 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str | |||
1047 | return ERR_PTR(-EIO); | 1038 | return ERR_PTR(-EIO); |
1048 | } | 1039 | } |
1049 | inode = ext3_iget(dir->i_sb, ino); | 1040 | inode = ext3_iget(dir->i_sb, ino); |
1050 | if (unlikely(IS_ERR(inode))) { | 1041 | if (IS_ERR(inode)) { |
1051 | if (PTR_ERR(inode) == -ESTALE) { | 1042 | if (PTR_ERR(inode) == -ESTALE) { |
1052 | ext3_error(dir->i_sb, __func__, | 1043 | ext3_error(dir->i_sb, __func__, |
1053 | "deleted inode referenced: %lu", | 1044 | "deleted inode referenced: %lu", |
@@ -1607,7 +1598,9 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1607 | if (err) | 1598 | if (err) |
1608 | goto journal_error; | 1599 | goto journal_error; |
1609 | } | 1600 | } |
1610 | ext3_journal_dirty_metadata(handle, frames[0].bh); | 1601 | err = ext3_journal_dirty_metadata(handle, frames[0].bh); |
1602 | if (err) | ||
1603 | goto journal_error; | ||
1611 | } | 1604 | } |
1612 | de = do_split(handle, dir, &bh, frame, &hinfo, &err); | 1605 | de = do_split(handle, dir, &bh, frame, &hinfo, &err); |
1613 | if (!de) | 1606 | if (!de) |
@@ -1644,8 +1637,13 @@ static int ext3_delete_entry (handle_t *handle, | |||
1644 | if (!ext3_check_dir_entry("ext3_delete_entry", dir, de, bh, i)) | 1637 | if (!ext3_check_dir_entry("ext3_delete_entry", dir, de, bh, i)) |
1645 | return -EIO; | 1638 | return -EIO; |
1646 | if (de == de_del) { | 1639 | if (de == de_del) { |
1640 | int err; | ||
1641 | |||
1647 | BUFFER_TRACE(bh, "get_write_access"); | 1642 | BUFFER_TRACE(bh, "get_write_access"); |
1648 | ext3_journal_get_write_access(handle, bh); | 1643 | err = ext3_journal_get_write_access(handle, bh); |
1644 | if (err) | ||
1645 | goto journal_error; | ||
1646 | |||
1649 | if (pde) | 1647 | if (pde) |
1650 | pde->rec_len = ext3_rec_len_to_disk( | 1648 | pde->rec_len = ext3_rec_len_to_disk( |
1651 | ext3_rec_len_from_disk(pde->rec_len) + | 1649 | ext3_rec_len_from_disk(pde->rec_len) + |
@@ -1654,7 +1652,12 @@ static int ext3_delete_entry (handle_t *handle, | |||
1654 | de->inode = 0; | 1652 | de->inode = 0; |
1655 | dir->i_version++; | 1653 | dir->i_version++; |
1656 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); | 1654 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); |
1657 | ext3_journal_dirty_metadata(handle, bh); | 1655 | err = ext3_journal_dirty_metadata(handle, bh); |
1656 | if (err) { | ||
1657 | journal_error: | ||
1658 | ext3_std_error(dir->i_sb, err); | ||
1659 | return err; | ||
1660 | } | ||
1658 | return 0; | 1661 | return 0; |
1659 | } | 1662 | } |
1660 | i += ext3_rec_len_from_disk(de->rec_len); | 1663 | i += ext3_rec_len_from_disk(de->rec_len); |
@@ -1762,7 +1765,7 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) | |||
1762 | { | 1765 | { |
1763 | handle_t *handle; | 1766 | handle_t *handle; |
1764 | struct inode * inode; | 1767 | struct inode * inode; |
1765 | struct buffer_head * dir_block; | 1768 | struct buffer_head * dir_block = NULL; |
1766 | struct ext3_dir_entry_2 * de; | 1769 | struct ext3_dir_entry_2 * de; |
1767 | int err, retries = 0; | 1770 | int err, retries = 0; |
1768 | 1771 | ||
@@ -1790,15 +1793,14 @@ retry: | |||
1790 | inode->i_fop = &ext3_dir_operations; | 1793 | inode->i_fop = &ext3_dir_operations; |
1791 | inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; | 1794 | inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; |
1792 | dir_block = ext3_bread (handle, inode, 0, 1, &err); | 1795 | dir_block = ext3_bread (handle, inode, 0, 1, &err); |
1793 | if (!dir_block) { | 1796 | if (!dir_block) |
1794 | drop_nlink(inode); /* is this nlink == 0? */ | 1797 | goto out_clear_inode; |
1795 | unlock_new_inode(inode); | 1798 | |
1796 | ext3_mark_inode_dirty(handle, inode); | ||
1797 | iput (inode); | ||
1798 | goto out_stop; | ||
1799 | } | ||
1800 | BUFFER_TRACE(dir_block, "get_write_access"); | 1799 | BUFFER_TRACE(dir_block, "get_write_access"); |
1801 | ext3_journal_get_write_access(handle, dir_block); | 1800 | err = ext3_journal_get_write_access(handle, dir_block); |
1801 | if (err) | ||
1802 | goto out_clear_inode; | ||
1803 | |||
1802 | de = (struct ext3_dir_entry_2 *) dir_block->b_data; | 1804 | de = (struct ext3_dir_entry_2 *) dir_block->b_data; |
1803 | de->inode = cpu_to_le32(inode->i_ino); | 1805 | de->inode = cpu_to_le32(inode->i_ino); |
1804 | de->name_len = 1; | 1806 | de->name_len = 1; |
@@ -1814,11 +1816,16 @@ retry: | |||
1814 | ext3_set_de_type(dir->i_sb, de, S_IFDIR); | 1816 | ext3_set_de_type(dir->i_sb, de, S_IFDIR); |
1815 | inode->i_nlink = 2; | 1817 | inode->i_nlink = 2; |
1816 | BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata"); | 1818 | BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata"); |
1817 | ext3_journal_dirty_metadata(handle, dir_block); | 1819 | err = ext3_journal_dirty_metadata(handle, dir_block); |
1818 | brelse (dir_block); | 1820 | if (err) |
1819 | ext3_mark_inode_dirty(handle, inode); | 1821 | goto out_clear_inode; |
1820 | err = ext3_add_entry (handle, dentry, inode); | 1822 | |
1823 | err = ext3_mark_inode_dirty(handle, inode); | ||
1824 | if (!err) | ||
1825 | err = ext3_add_entry (handle, dentry, inode); | ||
1826 | |||
1821 | if (err) { | 1827 | if (err) { |
1828 | out_clear_inode: | ||
1822 | inode->i_nlink = 0; | 1829 | inode->i_nlink = 0; |
1823 | unlock_new_inode(inode); | 1830 | unlock_new_inode(inode); |
1824 | ext3_mark_inode_dirty(handle, inode); | 1831 | ext3_mark_inode_dirty(handle, inode); |
@@ -1827,10 +1834,14 @@ retry: | |||
1827 | } | 1834 | } |
1828 | inc_nlink(dir); | 1835 | inc_nlink(dir); |
1829 | ext3_update_dx_flag(dir); | 1836 | ext3_update_dx_flag(dir); |
1830 | ext3_mark_inode_dirty(handle, dir); | 1837 | err = ext3_mark_inode_dirty(handle, dir); |
1838 | if (err) | ||
1839 | goto out_clear_inode; | ||
1840 | |||
1831 | d_instantiate(dentry, inode); | 1841 | d_instantiate(dentry, inode); |
1832 | unlock_new_inode(inode); | 1842 | unlock_new_inode(inode); |
1833 | out_stop: | 1843 | out_stop: |
1844 | brelse(dir_block); | ||
1834 | ext3_journal_stop(handle); | 1845 | ext3_journal_stop(handle); |
1835 | if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) | 1846 | if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) |
1836 | goto retry; | 1847 | goto retry; |
@@ -2260,7 +2271,7 @@ retry: | |||
2260 | 2271 | ||
2261 | inode->i_ctime = CURRENT_TIME_SEC; | 2272 | inode->i_ctime = CURRENT_TIME_SEC; |
2262 | inc_nlink(inode); | 2273 | inc_nlink(inode); |
2263 | atomic_inc(&inode->i_count); | 2274 | ihold(inode); |
2264 | 2275 | ||
2265 | err = ext3_add_entry(handle, dentry, inode); | 2276 | err = ext3_add_entry(handle, dentry, inode); |
2266 | if (!err) { | 2277 | if (!err) { |
@@ -2353,7 +2364,9 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2353 | goto end_rename; | 2364 | goto end_rename; |
2354 | } else { | 2365 | } else { |
2355 | BUFFER_TRACE(new_bh, "get write access"); | 2366 | BUFFER_TRACE(new_bh, "get write access"); |
2356 | ext3_journal_get_write_access(handle, new_bh); | 2367 | retval = ext3_journal_get_write_access(handle, new_bh); |
2368 | if (retval) | ||
2369 | goto journal_error; | ||
2357 | new_de->inode = cpu_to_le32(old_inode->i_ino); | 2370 | new_de->inode = cpu_to_le32(old_inode->i_ino); |
2358 | if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb, | 2371 | if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb, |
2359 | EXT3_FEATURE_INCOMPAT_FILETYPE)) | 2372 | EXT3_FEATURE_INCOMPAT_FILETYPE)) |
@@ -2362,7 +2375,9 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2362 | new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME_SEC; | 2375 | new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME_SEC; |
2363 | ext3_mark_inode_dirty(handle, new_dir); | 2376 | ext3_mark_inode_dirty(handle, new_dir); |
2364 | BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata"); | 2377 | BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata"); |
2365 | ext3_journal_dirty_metadata(handle, new_bh); | 2378 | retval = ext3_journal_dirty_metadata(handle, new_bh); |
2379 | if (retval) | ||
2380 | goto journal_error; | ||
2366 | brelse(new_bh); | 2381 | brelse(new_bh); |
2367 | new_bh = NULL; | 2382 | new_bh = NULL; |
2368 | } | 2383 | } |
@@ -2411,10 +2426,17 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2411 | ext3_update_dx_flag(old_dir); | 2426 | ext3_update_dx_flag(old_dir); |
2412 | if (dir_bh) { | 2427 | if (dir_bh) { |
2413 | BUFFER_TRACE(dir_bh, "get_write_access"); | 2428 | BUFFER_TRACE(dir_bh, "get_write_access"); |
2414 | ext3_journal_get_write_access(handle, dir_bh); | 2429 | retval = ext3_journal_get_write_access(handle, dir_bh); |
2430 | if (retval) | ||
2431 | goto journal_error; | ||
2415 | PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino); | 2432 | PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino); |
2416 | BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata"); | 2433 | BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata"); |
2417 | ext3_journal_dirty_metadata(handle, dir_bh); | 2434 | retval = ext3_journal_dirty_metadata(handle, dir_bh); |
2435 | if (retval) { | ||
2436 | journal_error: | ||
2437 | ext3_std_error(new_dir->i_sb, retval); | ||
2438 | goto end_rename; | ||
2439 | } | ||
2418 | drop_nlink(old_dir); | 2440 | drop_nlink(old_dir); |
2419 | if (new_inode) { | 2441 | if (new_inode) { |
2420 | drop_nlink(new_inode); | 2442 | drop_nlink(new_inode); |