diff options
author | Theodore Ts'o <tytso@mit.edu> | 2013-02-09 16:27:09 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-02-09 16:27:09 -0500 |
commit | 1139575a927010390c6b38e4215a6d741b056074 (patch) | |
tree | 0fb06dbe63ed7aaa2e14ce4c03587fd9c4f87b63 /fs | |
parent | 95eaefbdececae5e781d76d03fe7472a857c8c7a (diff) |
ext4: start handle at the last possible moment when creating inodes
In ext4_{create,mknod,mkdir,symlink}(), don't start the journal handle
until the inode has been succesfully allocated. In order to do this,
we need to start the handle in the ext4_new_inode(). So create a new
variant of this function, ext4_new_inode_start_handle(), so the handle
can be created at the last possible minute, before we need to modify
the inode allocation bitmap block.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4.h | 17 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 15 | ||||
-rw-r--r-- | fs/ext4/namei.c | 94 |
3 files changed, 71 insertions, 55 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 61ecf059f70c..fc1c0375c9f2 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -2004,9 +2004,20 @@ extern int ext4fs_dirhash(const char *name, int len, struct | |||
2004 | dx_hash_info *hinfo); | 2004 | dx_hash_info *hinfo); |
2005 | 2005 | ||
2006 | /* ialloc.c */ | 2006 | /* ialloc.c */ |
2007 | extern struct inode *ext4_new_inode(handle_t *, struct inode *, umode_t, | 2007 | extern struct inode *__ext4_new_inode(handle_t *, struct inode *, umode_t, |
2008 | const struct qstr *qstr, __u32 goal, | 2008 | const struct qstr *qstr, __u32 goal, |
2009 | uid_t *owner); | 2009 | uid_t *owner, int handle_type, |
2010 | unsigned int line_no, int nblocks); | ||
2011 | |||
2012 | #define ext4_new_inode(handle, dir, mode, qstr, goal, owner) \ | ||
2013 | __ext4_new_inode((handle), (dir), (mode), (qstr), (goal), (owner), \ | ||
2014 | 0, 0, 0) | ||
2015 | #define ext4_new_inode_start_handle(dir, mode, qstr, goal, owner, \ | ||
2016 | type, nblocks) \ | ||
2017 | __ext4_new_inode(NULL, (dir), (mode), (qstr), (goal), (owner), \ | ||
2018 | (type), __LINE__, (nblocks)) | ||
2019 | |||
2020 | |||
2010 | extern void ext4_free_inode(handle_t *, struct inode *); | 2021 | extern void ext4_free_inode(handle_t *, struct inode *); |
2011 | extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); | 2022 | extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); |
2012 | extern unsigned long ext4_count_free_inodes(struct super_block *); | 2023 | extern unsigned long ext4_count_free_inodes(struct super_block *); |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 10bd6fecc9ff..91d8fe3aced3 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -634,8 +634,10 @@ static int find_group_other(struct super_block *sb, struct inode *parent, | |||
634 | * For other inodes, search forward from the parent directory's block | 634 | * For other inodes, search forward from the parent directory's block |
635 | * group to find a free inode. | 635 | * group to find a free inode. |
636 | */ | 636 | */ |
637 | struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode, | 637 | struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, |
638 | const struct qstr *qstr, __u32 goal, uid_t *owner) | 638 | umode_t mode, const struct qstr *qstr, |
639 | __u32 goal, uid_t *owner, int handle_type, | ||
640 | unsigned int line_no, int nblocks) | ||
639 | { | 641 | { |
640 | struct super_block *sb; | 642 | struct super_block *sb; |
641 | struct buffer_head *inode_bitmap_bh = NULL; | 643 | struct buffer_head *inode_bitmap_bh = NULL; |
@@ -725,6 +727,15 @@ repeat_in_this_group: | |||
725 | "inode=%lu", ino + 1); | 727 | "inode=%lu", ino + 1); |
726 | continue; | 728 | continue; |
727 | } | 729 | } |
730 | if (!handle) { | ||
731 | BUG_ON(nblocks <= 0); | ||
732 | handle = __ext4_journal_start_sb(dir->i_sb, line_no, | ||
733 | handle_type, nblocks); | ||
734 | if (IS_ERR(handle)) { | ||
735 | err = PTR_ERR(handle); | ||
736 | goto fail; | ||
737 | } | ||
738 | } | ||
728 | BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); | 739 | BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); |
729 | err = ext4_journal_get_write_access(handle, inode_bitmap_bh); | 740 | err = ext4_journal_get_write_access(handle, inode_bitmap_bh); |
730 | if (err) | 741 | if (err) |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 5f3d2b569c63..3e1529c39808 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -2257,30 +2257,28 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
2257 | { | 2257 | { |
2258 | handle_t *handle; | 2258 | handle_t *handle; |
2259 | struct inode *inode; | 2259 | struct inode *inode; |
2260 | int err, retries = 0; | 2260 | int err, credits, retries = 0; |
2261 | 2261 | ||
2262 | dquot_initialize(dir); | 2262 | dquot_initialize(dir); |
2263 | 2263 | ||
2264 | credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | ||
2265 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | ||
2266 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); | ||
2264 | retry: | 2267 | retry: |
2265 | handle = ext4_journal_start(dir, EXT4_HT_DIR, | 2268 | inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0, |
2266 | (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | 2269 | NULL, EXT4_HT_DIR, credits); |
2267 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 2270 | handle = ext4_journal_current_handle(); |
2268 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb))); | ||
2269 | if (IS_ERR(handle)) | ||
2270 | return PTR_ERR(handle); | ||
2271 | |||
2272 | if (IS_DIRSYNC(dir)) | ||
2273 | ext4_handle_sync(handle); | ||
2274 | |||
2275 | inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0, NULL); | ||
2276 | err = PTR_ERR(inode); | 2271 | err = PTR_ERR(inode); |
2277 | if (!IS_ERR(inode)) { | 2272 | if (!IS_ERR(inode)) { |
2278 | inode->i_op = &ext4_file_inode_operations; | 2273 | inode->i_op = &ext4_file_inode_operations; |
2279 | inode->i_fop = &ext4_file_operations; | 2274 | inode->i_fop = &ext4_file_operations; |
2280 | ext4_set_aops(inode); | 2275 | ext4_set_aops(inode); |
2281 | err = ext4_add_nondir(handle, dentry, inode); | 2276 | err = ext4_add_nondir(handle, dentry, inode); |
2277 | if (!err && IS_DIRSYNC(dir)) | ||
2278 | ext4_handle_sync(handle); | ||
2282 | } | 2279 | } |
2283 | ext4_journal_stop(handle); | 2280 | if (handle) |
2281 | ext4_journal_stop(handle); | ||
2284 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) | 2282 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
2285 | goto retry; | 2283 | goto retry; |
2286 | return err; | 2284 | return err; |
@@ -2291,32 +2289,30 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry, | |||
2291 | { | 2289 | { |
2292 | handle_t *handle; | 2290 | handle_t *handle; |
2293 | struct inode *inode; | 2291 | struct inode *inode; |
2294 | int err, retries = 0; | 2292 | int err, credits, retries = 0; |
2295 | 2293 | ||
2296 | if (!new_valid_dev(rdev)) | 2294 | if (!new_valid_dev(rdev)) |
2297 | return -EINVAL; | 2295 | return -EINVAL; |
2298 | 2296 | ||
2299 | dquot_initialize(dir); | 2297 | dquot_initialize(dir); |
2300 | 2298 | ||
2299 | credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | ||
2300 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | ||
2301 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); | ||
2301 | retry: | 2302 | retry: |
2302 | handle = ext4_journal_start(dir, EXT4_HT_DIR, | 2303 | inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0, |
2303 | (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | 2304 | NULL, EXT4_HT_DIR, credits); |
2304 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 2305 | handle = ext4_journal_current_handle(); |
2305 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb))); | ||
2306 | if (IS_ERR(handle)) | ||
2307 | return PTR_ERR(handle); | ||
2308 | |||
2309 | if (IS_DIRSYNC(dir)) | ||
2310 | ext4_handle_sync(handle); | ||
2311 | |||
2312 | inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0, NULL); | ||
2313 | err = PTR_ERR(inode); | 2306 | err = PTR_ERR(inode); |
2314 | if (!IS_ERR(inode)) { | 2307 | if (!IS_ERR(inode)) { |
2315 | init_special_inode(inode, inode->i_mode, rdev); | 2308 | init_special_inode(inode, inode->i_mode, rdev); |
2316 | inode->i_op = &ext4_special_inode_operations; | 2309 | inode->i_op = &ext4_special_inode_operations; |
2317 | err = ext4_add_nondir(handle, dentry, inode); | 2310 | err = ext4_add_nondir(handle, dentry, inode); |
2311 | if (!err && IS_DIRSYNC(dir)) | ||
2312 | ext4_handle_sync(handle); | ||
2318 | } | 2313 | } |
2319 | ext4_journal_stop(handle); | 2314 | if (handle) |
2315 | ext4_journal_stop(handle); | ||
2320 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) | 2316 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
2321 | goto retry; | 2317 | goto retry; |
2322 | return err; | 2318 | return err; |
@@ -2408,26 +2404,21 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
2408 | { | 2404 | { |
2409 | handle_t *handle; | 2405 | handle_t *handle; |
2410 | struct inode *inode; | 2406 | struct inode *inode; |
2411 | int err, retries = 0; | 2407 | int err, credits, retries = 0; |
2412 | 2408 | ||
2413 | if (EXT4_DIR_LINK_MAX(dir)) | 2409 | if (EXT4_DIR_LINK_MAX(dir)) |
2414 | return -EMLINK; | 2410 | return -EMLINK; |
2415 | 2411 | ||
2416 | dquot_initialize(dir); | 2412 | dquot_initialize(dir); |
2417 | 2413 | ||
2414 | credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | ||
2415 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | ||
2416 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); | ||
2418 | retry: | 2417 | retry: |
2419 | handle = ext4_journal_start(dir, EXT4_HT_DIR, | 2418 | inode = ext4_new_inode_start_handle(dir, S_IFDIR | mode, |
2420 | (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | 2419 | &dentry->d_name, |
2421 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 2420 | 0, NULL, EXT4_HT_DIR, credits); |
2422 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb))); | 2421 | handle = ext4_journal_current_handle(); |
2423 | if (IS_ERR(handle)) | ||
2424 | return PTR_ERR(handle); | ||
2425 | |||
2426 | if (IS_DIRSYNC(dir)) | ||
2427 | ext4_handle_sync(handle); | ||
2428 | |||
2429 | inode = ext4_new_inode(handle, dir, S_IFDIR | mode, | ||
2430 | &dentry->d_name, 0, NULL); | ||
2431 | err = PTR_ERR(inode); | 2422 | err = PTR_ERR(inode); |
2432 | if (IS_ERR(inode)) | 2423 | if (IS_ERR(inode)) |
2433 | goto out_stop; | 2424 | goto out_stop; |
@@ -2455,8 +2446,12 @@ out_clear_inode: | |||
2455 | goto out_clear_inode; | 2446 | goto out_clear_inode; |
2456 | unlock_new_inode(inode); | 2447 | unlock_new_inode(inode); |
2457 | d_instantiate(dentry, inode); | 2448 | d_instantiate(dentry, inode); |
2449 | if (IS_DIRSYNC(dir)) | ||
2450 | ext4_handle_sync(handle); | ||
2451 | |||
2458 | out_stop: | 2452 | out_stop: |
2459 | ext4_journal_stop(handle); | 2453 | if (handle) |
2454 | ext4_journal_stop(handle); | ||
2460 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) | 2455 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
2461 | goto retry; | 2456 | goto retry; |
2462 | return err; | 2457 | return err; |
@@ -2883,15 +2878,10 @@ static int ext4_symlink(struct inode *dir, | |||
2883 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb); | 2878 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb); |
2884 | } | 2879 | } |
2885 | retry: | 2880 | retry: |
2886 | handle = ext4_journal_start(dir, EXT4_HT_DIR, credits); | 2881 | inode = ext4_new_inode_start_handle(dir, S_IFLNK|S_IRWXUGO, |
2887 | if (IS_ERR(handle)) | 2882 | &dentry->d_name, 0, NULL, |
2888 | return PTR_ERR(handle); | 2883 | EXT4_HT_DIR, credits); |
2889 | 2884 | handle = ext4_journal_current_handle(); | |
2890 | if (IS_DIRSYNC(dir)) | ||
2891 | ext4_handle_sync(handle); | ||
2892 | |||
2893 | inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO, | ||
2894 | &dentry->d_name, 0, NULL); | ||
2895 | err = PTR_ERR(inode); | 2885 | err = PTR_ERR(inode); |
2896 | if (IS_ERR(inode)) | 2886 | if (IS_ERR(inode)) |
2897 | goto out_stop; | 2887 | goto out_stop; |
@@ -2944,8 +2934,12 @@ retry: | |||
2944 | } | 2934 | } |
2945 | EXT4_I(inode)->i_disksize = inode->i_size; | 2935 | EXT4_I(inode)->i_disksize = inode->i_size; |
2946 | err = ext4_add_nondir(handle, dentry, inode); | 2936 | err = ext4_add_nondir(handle, dentry, inode); |
2937 | if (!err && IS_DIRSYNC(dir)) | ||
2938 | ext4_handle_sync(handle); | ||
2939 | |||
2947 | out_stop: | 2940 | out_stop: |
2948 | ext4_journal_stop(handle); | 2941 | if (handle) |
2942 | ext4_journal_stop(handle); | ||
2949 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) | 2943 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
2950 | goto retry; | 2944 | goto retry; |
2951 | return err; | 2945 | return err; |