aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs/dir.c
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2012-11-22 02:21:29 -0500
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2013-04-09 05:21:18 -0400
commit399368372ed9f3c396eadb5c2bbc98be8c774a39 (patch)
treeb496c910ebf04d95e5ad6cb1b65d8cbb45aeef89 /fs/f2fs/dir.c
parent1127a3d448bcf4de338e60a7cc695d54c5767433 (diff)
f2fs: introduce a new global lock scheme
In the previous version, f2fs uses global locks according to the usage types, such as directory operations, block allocation, block write, and so on. Reference the following lock types in f2fs.h. enum lock_type { RENAME, /* for renaming operations */ DENTRY_OPS, /* for directory operations */ DATA_WRITE, /* for data write */ DATA_NEW, /* for data allocation */ DATA_TRUNC, /* for data truncate */ NODE_NEW, /* for node allocation */ NODE_TRUNC, /* for node truncate */ NODE_WRITE, /* for node write */ NR_LOCK_TYPE, }; In that case, we lose the performance under the multi-threading environment, since every types of operations must be conducted one at a time. In order to address the problem, let's share the locks globally with a mutex array regardless of any types. So, let users grab a mutex and perform their jobs in parallel as much as possbile. For this, I propose a new global lock scheme as follows. 0. Data structure - f2fs_sb_info -> mutex_lock[NR_GLOBAL_LOCKS] - f2fs_sb_info -> node_write 1. mutex_lock_op(sbi) - try to get an avaiable lock from the array. - returns the index of the gottern lock variable. 2. mutex_unlock_op(sbi, index of the lock) - unlock the given index of the lock. 3. mutex_lock_all(sbi) - grab all the locks in the array before the checkpoint. 4. mutex_unlock_all(sbi) - release all the locks in the array after checkpoint. 5. block_operations() - call mutex_lock_all() - sync_dirty_dir_inodes() - grab node_write - sync_node_pages() Note that, the pairs of mutex_lock_op()/mutex_unlock_op() and mutex_lock_all()/mutex_unlock_all() should be used together. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs/dir.c')
-rw-r--r--fs/f2fs/dir.c105
1 files changed, 48 insertions, 57 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 2851ae6948a1..cd3342d4a3a7 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -249,9 +249,6 @@ ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr)
249void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, 249void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
250 struct page *page, struct inode *inode) 250 struct page *page, struct inode *inode)
251{ 251{
252 struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
253
254 mutex_lock_op(sbi, DENTRY_OPS);
255 lock_page(page); 252 lock_page(page);
256 wait_on_page_writeback(page); 253 wait_on_page_writeback(page);
257 de->ino = cpu_to_le32(inode->i_ino); 254 de->ino = cpu_to_le32(inode->i_ino);
@@ -265,7 +262,6 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
265 F2FS_I(inode)->i_pino = dir->i_ino; 262 F2FS_I(inode)->i_pino = dir->i_ino;
266 263
267 f2fs_put_page(page, 1); 264 f2fs_put_page(page, 1);
268 mutex_unlock_op(sbi, DENTRY_OPS);
269} 265}
270 266
271void init_dent_inode(const struct qstr *name, struct page *ipage) 267void init_dent_inode(const struct qstr *name, struct page *ipage)
@@ -284,6 +280,43 @@ void init_dent_inode(const struct qstr *name, struct page *ipage)
284 set_page_dirty(ipage); 280 set_page_dirty(ipage);
285} 281}
286 282
283static int make_empty_dir(struct inode *inode, struct inode *parent)
284{
285 struct page *dentry_page;
286 struct f2fs_dentry_block *dentry_blk;
287 struct f2fs_dir_entry *de;
288 void *kaddr;
289
290 dentry_page = get_new_data_page(inode, 0, true);
291 if (IS_ERR(dentry_page))
292 return PTR_ERR(dentry_page);
293
294 kaddr = kmap_atomic(dentry_page);
295 dentry_blk = (struct f2fs_dentry_block *)kaddr;
296
297 de = &dentry_blk->dentry[0];
298 de->name_len = cpu_to_le16(1);
299 de->hash_code = 0;
300 de->ino = cpu_to_le32(inode->i_ino);
301 memcpy(dentry_blk->filename[0], ".", 1);
302 set_de_type(de, inode);
303
304 de = &dentry_blk->dentry[1];
305 de->hash_code = 0;
306 de->name_len = cpu_to_le16(2);
307 de->ino = cpu_to_le32(parent->i_ino);
308 memcpy(dentry_blk->filename[1], "..", 2);
309 set_de_type(de, inode);
310
311 test_and_set_bit_le(0, &dentry_blk->dentry_bitmap);
312 test_and_set_bit_le(1, &dentry_blk->dentry_bitmap);
313 kunmap_atomic(kaddr);
314
315 set_page_dirty(dentry_page);
316 f2fs_put_page(dentry_page, 1);
317 return 0;
318}
319
287static int init_inode_metadata(struct inode *inode, 320static int init_inode_metadata(struct inode *inode,
288 struct inode *dir, const struct qstr *name) 321 struct inode *dir, const struct qstr *name)
289{ 322{
@@ -294,7 +327,7 @@ static int init_inode_metadata(struct inode *inode,
294 return err; 327 return err;
295 328
296 if (S_ISDIR(inode->i_mode)) { 329 if (S_ISDIR(inode->i_mode)) {
297 err = f2fs_make_empty(inode, dir); 330 err = make_empty_dir(inode, dir);
298 if (err) { 331 if (err) {
299 remove_inode_page(inode); 332 remove_inode_page(inode);
300 return err; 333 return err;
@@ -317,7 +350,7 @@ static int init_inode_metadata(struct inode *inode,
317 } 350 }
318 if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) { 351 if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
319 inc_nlink(inode); 352 inc_nlink(inode);
320 f2fs_write_inode(inode, NULL); 353 update_inode_page(inode);
321 } 354 }
322 return 0; 355 return 0;
323} 356}
@@ -341,7 +374,7 @@ static void update_parent_metadata(struct inode *dir, struct inode *inode,
341 } 374 }
342 375
343 if (need_dir_update) 376 if (need_dir_update)
344 f2fs_write_inode(dir, NULL); 377 update_inode_page(dir);
345 else 378 else
346 mark_inode_dirty(dir); 379 mark_inode_dirty(dir);
347 380
@@ -373,6 +406,10 @@ next:
373 goto next; 406 goto next;
374} 407}
375 408
409/*
410 * Caller should grab and release a mutex by calling mutex_lock_op() and
411 * mutex_unlock_op().
412 */
376int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *inode) 413int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *inode)
377{ 414{
378 unsigned int bit_pos; 415 unsigned int bit_pos;
@@ -382,7 +419,6 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *in
382 f2fs_hash_t dentry_hash; 419 f2fs_hash_t dentry_hash;
383 struct f2fs_dir_entry *de; 420 struct f2fs_dir_entry *de;
384 unsigned int nbucket, nblock; 421 unsigned int nbucket, nblock;
385 struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
386 size_t namelen = name->len; 422 size_t namelen = name->len;
387 struct page *dentry_page = NULL; 423 struct page *dentry_page = NULL;
388 struct f2fs_dentry_block *dentry_blk = NULL; 424 struct f2fs_dentry_block *dentry_blk = NULL;
@@ -412,12 +448,9 @@ start:
412 bidx = dir_block_index(level, (le32_to_cpu(dentry_hash) % nbucket)); 448 bidx = dir_block_index(level, (le32_to_cpu(dentry_hash) % nbucket));
413 449
414 for (block = bidx; block <= (bidx + nblock - 1); block++) { 450 for (block = bidx; block <= (bidx + nblock - 1); block++) {
415 mutex_lock_op(sbi, DENTRY_OPS);
416 dentry_page = get_new_data_page(dir, block, true); 451 dentry_page = get_new_data_page(dir, block, true);
417 if (IS_ERR(dentry_page)) { 452 if (IS_ERR(dentry_page))
418 mutex_unlock_op(sbi, DENTRY_OPS);
419 return PTR_ERR(dentry_page); 453 return PTR_ERR(dentry_page);
420 }
421 454
422 dentry_blk = kmap(dentry_page); 455 dentry_blk = kmap(dentry_page);
423 bit_pos = room_for_filename(dentry_blk, slots); 456 bit_pos = room_for_filename(dentry_blk, slots);
@@ -426,7 +459,6 @@ start:
426 459
427 kunmap(dentry_page); 460 kunmap(dentry_page);
428 f2fs_put_page(dentry_page, 1); 461 f2fs_put_page(dentry_page, 1);
429 mutex_unlock_op(sbi, DENTRY_OPS);
430 } 462 }
431 463
432 /* Move to next level to find the empty slot for new dentry */ 464 /* Move to next level to find the empty slot for new dentry */
@@ -456,7 +488,6 @@ add_dentry:
456fail: 488fail:
457 kunmap(dentry_page); 489 kunmap(dentry_page);
458 f2fs_put_page(dentry_page, 1); 490 f2fs_put_page(dentry_page, 1);
459 mutex_unlock_op(sbi, DENTRY_OPS);
460 return err; 491 return err;
461} 492}
462 493
@@ -476,8 +507,6 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
476 void *kaddr = page_address(page); 507 void *kaddr = page_address(page);
477 int i; 508 int i;
478 509
479 mutex_lock_op(sbi, DENTRY_OPS);
480
481 lock_page(page); 510 lock_page(page);
482 wait_on_page_writeback(page); 511 wait_on_page_writeback(page);
483 512
@@ -497,7 +526,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
497 526
498 if (inode && S_ISDIR(inode->i_mode)) { 527 if (inode && S_ISDIR(inode->i_mode)) {
499 drop_nlink(dir); 528 drop_nlink(dir);
500 f2fs_write_inode(dir, NULL); 529 update_inode_page(dir);
501 } else { 530 } else {
502 mark_inode_dirty(dir); 531 mark_inode_dirty(dir);
503 } 532 }
@@ -509,7 +538,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
509 drop_nlink(inode); 538 drop_nlink(inode);
510 i_size_write(inode, 0); 539 i_size_write(inode, 0);
511 } 540 }
512 f2fs_write_inode(inode, NULL); 541 update_inode_page(inode);
542
513 if (inode->i_nlink == 0) 543 if (inode->i_nlink == 0)
514 add_orphan_inode(sbi, inode->i_ino); 544 add_orphan_inode(sbi, inode->i_ino);
515 } 545 }
@@ -522,45 +552,6 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
522 inode_dec_dirty_dents(dir); 552 inode_dec_dirty_dents(dir);
523 } 553 }
524 f2fs_put_page(page, 1); 554 f2fs_put_page(page, 1);
525
526 mutex_unlock_op(sbi, DENTRY_OPS);
527}
528
529int f2fs_make_empty(struct inode *inode, struct inode *parent)
530{
531 struct page *dentry_page;
532 struct f2fs_dentry_block *dentry_blk;
533 struct f2fs_dir_entry *de;
534 void *kaddr;
535
536 dentry_page = get_new_data_page(inode, 0, true);
537 if (IS_ERR(dentry_page))
538 return PTR_ERR(dentry_page);
539
540 kaddr = kmap_atomic(dentry_page);
541 dentry_blk = (struct f2fs_dentry_block *)kaddr;
542
543 de = &dentry_blk->dentry[0];
544 de->name_len = cpu_to_le16(1);
545 de->hash_code = f2fs_dentry_hash(".", 1);
546 de->ino = cpu_to_le32(inode->i_ino);
547 memcpy(dentry_blk->filename[0], ".", 1);
548 set_de_type(de, inode);
549
550 de = &dentry_blk->dentry[1];
551 de->hash_code = f2fs_dentry_hash("..", 2);
552 de->name_len = cpu_to_le16(2);
553 de->ino = cpu_to_le32(parent->i_ino);
554 memcpy(dentry_blk->filename[1], "..", 2);
555 set_de_type(de, inode);
556
557 test_and_set_bit_le(0, &dentry_blk->dentry_bitmap);
558 test_and_set_bit_le(1, &dentry_blk->dentry_bitmap);
559 kunmap_atomic(kaddr);
560
561 set_page_dirty(dentry_page);
562 f2fs_put_page(dentry_page, 1);
563 return 0;
564} 555}
565 556
566bool f2fs_empty_dir(struct inode *dir) 557bool f2fs_empty_dir(struct inode *dir)