aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorTao Ma <boyu.mt@taobao.com>2012-12-10 14:05:57 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-12-10 14:05:57 -0500
commita774f9c20e08643fc0e6c48b0419ad7657ed0c04 (patch)
treede774f5b58346174e1e867dbf49f7c4604544d48 /fs/ext4
parent9c3569b50f12e47cc5e907b5e37e4a45c0c10b43 (diff)
ext4: make ext4_init_dot_dotdot for inline dir usage
Currently, the initialization of dot and dotdot are encapsulated in ext4_mkdir and also bond with dir_block. So create a new function named ext4_init_new_dir and the initialization is moved to ext4_init_dot_dotdot. Now it will called either in the normal non-inline case(rec_len of ".." will cover the whole block) or when we converting an inline dir to a block(rec len of ".." will be the real length). The start of the next entry is also returned for inline dir usage. Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/ext4.h4
-rw-r--r--fs/ext4/namei.c115
2 files changed, 75 insertions, 44 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 268636af7f5c..cf840146ce81 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2415,6 +2415,10 @@ extern void ext4_unwritten_wait(struct inode *inode);
2415extern const struct inode_operations ext4_dir_inode_operations; 2415extern const struct inode_operations ext4_dir_inode_operations;
2416extern const struct inode_operations ext4_special_inode_operations; 2416extern const struct inode_operations ext4_special_inode_operations;
2417extern struct dentry *ext4_get_parent(struct dentry *child); 2417extern struct dentry *ext4_get_parent(struct dentry *child);
2418extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
2419 struct ext4_dir_entry_2 *de,
2420 int blocksize, int csum_size,
2421 unsigned int parent_ino, int dotdot_real_len);
2418 2422
2419/* symlink.c */ 2423/* symlink.c */
2420extern const struct inode_operations ext4_symlink_inode_operations; 2424extern const struct inode_operations ext4_symlink_inode_operations;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 88e9a2c7e328..edb9f10c1455 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2230,21 +2230,87 @@ retry:
2230 return err; 2230 return err;
2231} 2231}
2232 2232
2233static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 2233struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
2234 struct ext4_dir_entry_2 *de,
2235 int blocksize, int csum_size,
2236 unsigned int parent_ino, int dotdot_real_len)
2237{
2238 de->inode = cpu_to_le32(inode->i_ino);
2239 de->name_len = 1;
2240 de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len),
2241 blocksize);
2242 strcpy(de->name, ".");
2243 ext4_set_de_type(inode->i_sb, de, S_IFDIR);
2244
2245 de = ext4_next_entry(de, blocksize);
2246 de->inode = cpu_to_le32(parent_ino);
2247 de->name_len = 2;
2248 if (!dotdot_real_len)
2249 de->rec_len = ext4_rec_len_to_disk(blocksize -
2250 (csum_size + EXT4_DIR_REC_LEN(1)),
2251 blocksize);
2252 else
2253 de->rec_len = ext4_rec_len_to_disk(
2254 EXT4_DIR_REC_LEN(de->name_len), blocksize);
2255 strcpy(de->name, "..");
2256 ext4_set_de_type(inode->i_sb, de, S_IFDIR);
2257
2258 return ext4_next_entry(de, blocksize);
2259}
2260
2261static int ext4_init_new_dir(handle_t *handle, struct inode *dir,
2262 struct inode *inode)
2234{ 2263{
2235 handle_t *handle;
2236 struct inode *inode;
2237 struct buffer_head *dir_block = NULL; 2264 struct buffer_head *dir_block = NULL;
2238 struct ext4_dir_entry_2 *de; 2265 struct ext4_dir_entry_2 *de;
2239 struct ext4_dir_entry_tail *t; 2266 struct ext4_dir_entry_tail *t;
2240 unsigned int blocksize = dir->i_sb->s_blocksize; 2267 unsigned int blocksize = dir->i_sb->s_blocksize;
2241 int csum_size = 0; 2268 int csum_size = 0;
2242 int err, retries = 0; 2269 int err;
2243 2270
2244 if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, 2271 if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb,
2245 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) 2272 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
2246 csum_size = sizeof(struct ext4_dir_entry_tail); 2273 csum_size = sizeof(struct ext4_dir_entry_tail);
2247 2274
2275 inode->i_size = EXT4_I(inode)->i_disksize = blocksize;
2276 dir_block = ext4_bread(handle, inode, 0, 1, &err);
2277 if (!(dir_block = ext4_bread(handle, inode, 0, 1, &err))) {
2278 if (!err) {
2279 err = -EIO;
2280 ext4_error(inode->i_sb,
2281 "Directory hole detected on inode %lu\n",
2282 inode->i_ino);
2283 }
2284 goto out;
2285 }
2286 BUFFER_TRACE(dir_block, "get_write_access");
2287 err = ext4_journal_get_write_access(handle, dir_block);
2288 if (err)
2289 goto out;
2290 de = (struct ext4_dir_entry_2 *)dir_block->b_data;
2291 ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0);
2292 set_nlink(inode, 2);
2293 if (csum_size) {
2294 t = EXT4_DIRENT_TAIL(dir_block->b_data, blocksize);
2295 initialize_dirent_tail(t, blocksize);
2296 }
2297
2298 BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
2299 err = ext4_handle_dirty_dirent_node(handle, inode, dir_block);
2300 if (err)
2301 goto out;
2302 set_buffer_verified(dir_block);
2303out:
2304 brelse(dir_block);
2305 return err;
2306}
2307
2308static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
2309{
2310 handle_t *handle;
2311 struct inode *inode;
2312 int err, retries = 0;
2313
2248 if (EXT4_DIR_LINK_MAX(dir)) 2314 if (EXT4_DIR_LINK_MAX(dir))
2249 return -EMLINK; 2315 return -EMLINK;
2250 2316
@@ -2268,47 +2334,9 @@ retry:
2268 2334
2269 inode->i_op = &ext4_dir_inode_operations; 2335 inode->i_op = &ext4_dir_inode_operations;
2270 inode->i_fop = &ext4_dir_operations; 2336 inode->i_fop = &ext4_dir_operations;
2271 inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize; 2337 err = ext4_init_new_dir(handle, dir, inode);
2272 if (!(dir_block = ext4_bread(handle, inode, 0, 1, &err))) {
2273 if (!err) {
2274 err = -EIO;
2275 ext4_error(inode->i_sb,
2276 "Directory hole detected on inode %lu\n",
2277 inode->i_ino);
2278 }
2279 goto out_clear_inode;
2280 }
2281 BUFFER_TRACE(dir_block, "get_write_access");
2282 err = ext4_journal_get_write_access(handle, dir_block);
2283 if (err) 2338 if (err)
2284 goto out_clear_inode; 2339 goto out_clear_inode;
2285 de = (struct ext4_dir_entry_2 *) dir_block->b_data;
2286 de->inode = cpu_to_le32(inode->i_ino);
2287 de->name_len = 1;
2288 de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len),
2289 blocksize);
2290 strcpy(de->name, ".");
2291 ext4_set_de_type(dir->i_sb, de, S_IFDIR);
2292 de = ext4_next_entry(de, blocksize);
2293 de->inode = cpu_to_le32(dir->i_ino);
2294 de->rec_len = ext4_rec_len_to_disk(blocksize -
2295 (csum_size + EXT4_DIR_REC_LEN(1)),
2296 blocksize);
2297 de->name_len = 2;
2298 strcpy(de->name, "..");
2299 ext4_set_de_type(dir->i_sb, de, S_IFDIR);
2300 set_nlink(inode, 2);
2301
2302 if (csum_size) {
2303 t = EXT4_DIRENT_TAIL(dir_block->b_data, blocksize);
2304 initialize_dirent_tail(t, blocksize);
2305 }
2306
2307 BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
2308 err = ext4_handle_dirty_dirent_node(handle, inode, dir_block);
2309 if (err)
2310 goto out_clear_inode;
2311 set_buffer_verified(dir_block);
2312 err = ext4_mark_inode_dirty(handle, inode); 2340 err = ext4_mark_inode_dirty(handle, inode);
2313 if (!err) 2341 if (!err)
2314 err = ext4_add_entry(handle, dentry, inode); 2342 err = ext4_add_entry(handle, dentry, inode);
@@ -2328,7 +2356,6 @@ out_clear_inode:
2328 unlock_new_inode(inode); 2356 unlock_new_inode(inode);
2329 d_instantiate(dentry, inode); 2357 d_instantiate(dentry, inode);
2330out_stop: 2358out_stop:
2331 brelse(dir_block);
2332 ext4_journal_stop(handle); 2359 ext4_journal_stop(handle);
2333 if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) 2360 if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
2334 goto retry; 2361 goto retry;