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/ext4/namei.c | |
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/ext4/namei.c')
-rw-r--r-- | fs/ext4/namei.c | 94 |
1 files changed, 44 insertions, 50 deletions
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; |