Commit 1139575a927010390c6b38e4215a6d741b056074
1 parent
95eaefbdec
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 3 changed files with 71 additions and 55 deletions Side-by-side Diff
fs/ext4/ext4.h
... | ... | @@ -2004,9 +2004,20 @@ |
2004 | 2004 | dx_hash_info *hinfo); |
2005 | 2005 | |
2006 | 2006 | /* ialloc.c */ |
2007 | -extern struct inode *ext4_new_inode(handle_t *, struct inode *, umode_t, | |
2008 | - const struct qstr *qstr, __u32 goal, | |
2009 | - uid_t *owner); | |
2007 | +extern struct inode *__ext4_new_inode(handle_t *, struct inode *, umode_t, | |
2008 | + const struct qstr *qstr, __u32 goal, | |
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 | 2021 | extern void ext4_free_inode(handle_t *, struct inode *); |
2011 | 2022 | extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); |
2012 | 2023 | extern unsigned long ext4_count_free_inodes(struct super_block *); |
fs/ext4/ialloc.c
... | ... | @@ -634,8 +634,10 @@ |
634 | 634 | * For other inodes, search forward from the parent directory's block |
635 | 635 | * group to find a free inode. |
636 | 636 | */ |
637 | -struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode, | |
638 | - const struct qstr *qstr, __u32 goal, uid_t *owner) | |
637 | +struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, | |
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 | 642 | struct super_block *sb; |
641 | 643 | struct buffer_head *inode_bitmap_bh = NULL; |
... | ... | @@ -724,6 +726,15 @@ |
724 | 726 | ext4_error(sb, "reserved inode found cleared - " |
725 | 727 | "inode=%lu", ino + 1); |
726 | 728 | continue; |
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 | + } | |
727 | 738 | } |
728 | 739 | BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); |
729 | 740 | err = ext4_journal_get_write_access(handle, inode_bitmap_bh); |
fs/ext4/namei.c
... | ... | @@ -2257,30 +2257,28 @@ |
2257 | 2257 | { |
2258 | 2258 | handle_t *handle; |
2259 | 2259 | struct inode *inode; |
2260 | - int err, retries = 0; | |
2260 | + int err, credits, retries = 0; | |
2261 | 2261 | |
2262 | 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 | 2267 | retry: |
2265 | - handle = ext4_journal_start(dir, EXT4_HT_DIR, | |
2266 | - (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | |
2267 | - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | |
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); | |
2268 | + inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0, | |
2269 | + NULL, EXT4_HT_DIR, credits); | |
2270 | + handle = ext4_journal_current_handle(); | |
2276 | 2271 | err = PTR_ERR(inode); |
2277 | 2272 | if (!IS_ERR(inode)) { |
2278 | 2273 | inode->i_op = &ext4_file_inode_operations; |
2279 | 2274 | inode->i_fop = &ext4_file_operations; |
2280 | 2275 | ext4_set_aops(inode); |
2281 | 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 | 2282 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
2285 | 2283 | goto retry; |
2286 | 2284 | return err; |
2287 | 2285 | |
2288 | 2286 | |
2289 | 2287 | |
2290 | 2288 | |
... | ... | @@ -2291,32 +2289,30 @@ |
2291 | 2289 | { |
2292 | 2290 | handle_t *handle; |
2293 | 2291 | struct inode *inode; |
2294 | - int err, retries = 0; | |
2292 | + int err, credits, retries = 0; | |
2295 | 2293 | |
2296 | 2294 | if (!new_valid_dev(rdev)) |
2297 | 2295 | return -EINVAL; |
2298 | 2296 | |
2299 | 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 | 2302 | retry: |
2302 | - handle = ext4_journal_start(dir, EXT4_HT_DIR, | |
2303 | - (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | |
2304 | - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | |
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); | |
2303 | + inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0, | |
2304 | + NULL, EXT4_HT_DIR, credits); | |
2305 | + handle = ext4_journal_current_handle(); | |
2313 | 2306 | err = PTR_ERR(inode); |
2314 | 2307 | if (!IS_ERR(inode)) { |
2315 | 2308 | init_special_inode(inode, inode->i_mode, rdev); |
2316 | 2309 | inode->i_op = &ext4_special_inode_operations; |
2317 | 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 | 2316 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
2321 | 2317 | goto retry; |
2322 | 2318 | return err; |
2323 | 2319 | |
2324 | 2320 | |
... | ... | @@ -2408,26 +2404,21 @@ |
2408 | 2404 | { |
2409 | 2405 | handle_t *handle; |
2410 | 2406 | struct inode *inode; |
2411 | - int err, retries = 0; | |
2407 | + int err, credits, retries = 0; | |
2412 | 2408 | |
2413 | 2409 | if (EXT4_DIR_LINK_MAX(dir)) |
2414 | 2410 | return -EMLINK; |
2415 | 2411 | |
2416 | 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 | 2417 | retry: |
2419 | - handle = ext4_journal_start(dir, EXT4_HT_DIR, | |
2420 | - (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + | |
2421 | - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + | |
2422 | - EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb))); | |
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); | |
2418 | + inode = ext4_new_inode_start_handle(dir, S_IFDIR | mode, | |
2419 | + &dentry->d_name, | |
2420 | + 0, NULL, EXT4_HT_DIR, credits); | |
2421 | + handle = ext4_journal_current_handle(); | |
2431 | 2422 | err = PTR_ERR(inode); |
2432 | 2423 | if (IS_ERR(inode)) |
2433 | 2424 | goto out_stop; |
2434 | 2425 | |
... | ... | @@ -2455,8 +2446,12 @@ |
2455 | 2446 | goto out_clear_inode; |
2456 | 2447 | unlock_new_inode(inode); |
2457 | 2448 | d_instantiate(dentry, inode); |
2449 | + if (IS_DIRSYNC(dir)) | |
2450 | + ext4_handle_sync(handle); | |
2451 | + | |
2458 | 2452 | out_stop: |
2459 | - ext4_journal_stop(handle); | |
2453 | + if (handle) | |
2454 | + ext4_journal_stop(handle); | |
2460 | 2455 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
2461 | 2456 | goto retry; |
2462 | 2457 | return err; |
... | ... | @@ -2883,15 +2878,10 @@ |
2883 | 2878 | EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb); |
2884 | 2879 | } |
2885 | 2880 | retry: |
2886 | - handle = ext4_journal_start(dir, EXT4_HT_DIR, credits); | |
2887 | - if (IS_ERR(handle)) | |
2888 | - return PTR_ERR(handle); | |
2889 | - | |
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); | |
2881 | + inode = ext4_new_inode_start_handle(dir, S_IFLNK|S_IRWXUGO, | |
2882 | + &dentry->d_name, 0, NULL, | |
2883 | + EXT4_HT_DIR, credits); | |
2884 | + handle = ext4_journal_current_handle(); | |
2895 | 2885 | err = PTR_ERR(inode); |
2896 | 2886 | if (IS_ERR(inode)) |
2897 | 2887 | goto out_stop; |
2898 | 2888 | |
... | ... | @@ -2944,8 +2934,12 @@ |
2944 | 2934 | } |
2945 | 2935 | EXT4_I(inode)->i_disksize = inode->i_size; |
2946 | 2936 | err = ext4_add_nondir(handle, dentry, inode); |
2937 | + if (!err && IS_DIRSYNC(dir)) | |
2938 | + ext4_handle_sync(handle); | |
2939 | + | |
2947 | 2940 | out_stop: |
2948 | - ext4_journal_stop(handle); | |
2941 | + if (handle) | |
2942 | + ext4_journal_stop(handle); | |
2949 | 2943 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
2950 | 2944 | goto retry; |
2951 | 2945 | return err; |