diff options
Diffstat (limited to 'fs/nilfs2/sufile.c')
-rw-r--r-- | fs/nilfs2/sufile.c | 203 |
1 files changed, 112 insertions, 91 deletions
diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index 37994d4a59cc..b6c36d0cc331 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c | |||
@@ -31,6 +31,16 @@ | |||
31 | #include "sufile.h" | 31 | #include "sufile.h" |
32 | 32 | ||
33 | 33 | ||
34 | struct nilfs_sufile_info { | ||
35 | struct nilfs_mdt_info mi; | ||
36 | unsigned long ncleansegs; | ||
37 | }; | ||
38 | |||
39 | static inline struct nilfs_sufile_info *NILFS_SUI(struct inode *sufile) | ||
40 | { | ||
41 | return (struct nilfs_sufile_info *)NILFS_MDT(sufile); | ||
42 | } | ||
43 | |||
34 | static inline unsigned long | 44 | static inline unsigned long |
35 | nilfs_sufile_segment_usages_per_block(const struct inode *sufile) | 45 | nilfs_sufile_segment_usages_per_block(const struct inode *sufile) |
36 | { | 46 | { |
@@ -62,14 +72,6 @@ nilfs_sufile_segment_usages_in_block(const struct inode *sufile, __u64 curr, | |||
62 | max - curr + 1); | 72 | max - curr + 1); |
63 | } | 73 | } |
64 | 74 | ||
65 | static inline struct nilfs_sufile_header * | ||
66 | nilfs_sufile_block_get_header(const struct inode *sufile, | ||
67 | struct buffer_head *bh, | ||
68 | void *kaddr) | ||
69 | { | ||
70 | return kaddr + bh_offset(bh); | ||
71 | } | ||
72 | |||
73 | static struct nilfs_segment_usage * | 75 | static struct nilfs_segment_usage * |
74 | nilfs_sufile_block_get_segment_usage(const struct inode *sufile, __u64 segnum, | 76 | nilfs_sufile_block_get_segment_usage(const struct inode *sufile, __u64 segnum, |
75 | struct buffer_head *bh, void *kaddr) | 77 | struct buffer_head *bh, void *kaddr) |
@@ -110,6 +112,15 @@ static void nilfs_sufile_mod_counter(struct buffer_head *header_bh, | |||
110 | } | 112 | } |
111 | 113 | ||
112 | /** | 114 | /** |
115 | * nilfs_sufile_get_ncleansegs - return the number of clean segments | ||
116 | * @sufile: inode of segment usage file | ||
117 | */ | ||
118 | unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile) | ||
119 | { | ||
120 | return NILFS_SUI(sufile)->ncleansegs; | ||
121 | } | ||
122 | |||
123 | /** | ||
113 | * nilfs_sufile_updatev - modify multiple segment usages at a time | 124 | * nilfs_sufile_updatev - modify multiple segment usages at a time |
114 | * @sufile: inode of segment usage file | 125 | * @sufile: inode of segment usage file |
115 | * @segnumv: array of segment numbers | 126 | * @segnumv: array of segment numbers |
@@ -270,7 +281,7 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) | |||
270 | if (ret < 0) | 281 | if (ret < 0) |
271 | goto out_sem; | 282 | goto out_sem; |
272 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); | 283 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); |
273 | header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr); | 284 | header = kaddr + bh_offset(header_bh); |
274 | ncleansegs = le64_to_cpu(header->sh_ncleansegs); | 285 | ncleansegs = le64_to_cpu(header->sh_ncleansegs); |
275 | last_alloc = le64_to_cpu(header->sh_last_alloc); | 286 | last_alloc = le64_to_cpu(header->sh_last_alloc); |
276 | kunmap_atomic(kaddr, KM_USER0); | 287 | kunmap_atomic(kaddr, KM_USER0); |
@@ -302,13 +313,13 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) | |||
302 | kunmap_atomic(kaddr, KM_USER0); | 313 | kunmap_atomic(kaddr, KM_USER0); |
303 | 314 | ||
304 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); | 315 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); |
305 | header = nilfs_sufile_block_get_header( | 316 | header = kaddr + bh_offset(header_bh); |
306 | sufile, header_bh, kaddr); | ||
307 | le64_add_cpu(&header->sh_ncleansegs, -1); | 317 | le64_add_cpu(&header->sh_ncleansegs, -1); |
308 | le64_add_cpu(&header->sh_ndirtysegs, 1); | 318 | le64_add_cpu(&header->sh_ndirtysegs, 1); |
309 | header->sh_last_alloc = cpu_to_le64(segnum); | 319 | header->sh_last_alloc = cpu_to_le64(segnum); |
310 | kunmap_atomic(kaddr, KM_USER0); | 320 | kunmap_atomic(kaddr, KM_USER0); |
311 | 321 | ||
322 | NILFS_SUI(sufile)->ncleansegs--; | ||
312 | nilfs_mdt_mark_buffer_dirty(header_bh); | 323 | nilfs_mdt_mark_buffer_dirty(header_bh); |
313 | nilfs_mdt_mark_buffer_dirty(su_bh); | 324 | nilfs_mdt_mark_buffer_dirty(su_bh); |
314 | nilfs_mdt_mark_dirty(sufile); | 325 | nilfs_mdt_mark_dirty(sufile); |
@@ -351,6 +362,8 @@ void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum, | |||
351 | kunmap_atomic(kaddr, KM_USER0); | 362 | kunmap_atomic(kaddr, KM_USER0); |
352 | 363 | ||
353 | nilfs_sufile_mod_counter(header_bh, -1, 1); | 364 | nilfs_sufile_mod_counter(header_bh, -1, 1); |
365 | NILFS_SUI(sufile)->ncleansegs--; | ||
366 | |||
354 | nilfs_mdt_mark_buffer_dirty(su_bh); | 367 | nilfs_mdt_mark_buffer_dirty(su_bh); |
355 | nilfs_mdt_mark_dirty(sufile); | 368 | nilfs_mdt_mark_dirty(sufile); |
356 | } | 369 | } |
@@ -380,6 +393,8 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum, | |||
380 | kunmap_atomic(kaddr, KM_USER0); | 393 | kunmap_atomic(kaddr, KM_USER0); |
381 | 394 | ||
382 | nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1); | 395 | nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1); |
396 | NILFS_SUI(sufile)->ncleansegs -= clean; | ||
397 | |||
383 | nilfs_mdt_mark_buffer_dirty(su_bh); | 398 | nilfs_mdt_mark_buffer_dirty(su_bh); |
384 | nilfs_mdt_mark_dirty(sufile); | 399 | nilfs_mdt_mark_dirty(sufile); |
385 | } | 400 | } |
@@ -409,79 +424,65 @@ void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum, | |||
409 | nilfs_mdt_mark_buffer_dirty(su_bh); | 424 | nilfs_mdt_mark_buffer_dirty(su_bh); |
410 | 425 | ||
411 | nilfs_sufile_mod_counter(header_bh, 1, sudirty ? (u64)-1 : 0); | 426 | nilfs_sufile_mod_counter(header_bh, 1, sudirty ? (u64)-1 : 0); |
427 | NILFS_SUI(sufile)->ncleansegs++; | ||
428 | |||
412 | nilfs_mdt_mark_dirty(sufile); | 429 | nilfs_mdt_mark_dirty(sufile); |
413 | } | 430 | } |
414 | 431 | ||
415 | /** | 432 | /** |
416 | * nilfs_sufile_get_segment_usage - get a segment usage | 433 | * nilfs_sufile_mark_dirty - mark the buffer having a segment usage dirty |
417 | * @sufile: inode of segment usage file | 434 | * @sufile: inode of segment usage file |
418 | * @segnum: segment number | 435 | * @segnum: segment number |
419 | * @sup: pointer to segment usage | ||
420 | * @bhp: pointer to buffer head | ||
421 | * | ||
422 | * Description: nilfs_sufile_get_segment_usage() acquires the segment usage | ||
423 | * specified by @segnum. | ||
424 | * | ||
425 | * Return Value: On success, 0 is returned, and the segment usage and the | ||
426 | * buffer head of the buffer on which the segment usage is located are stored | ||
427 | * in the place pointed by @sup and @bhp, respectively. On error, one of the | ||
428 | * following negative error codes is returned. | ||
429 | * | ||
430 | * %-EIO - I/O error. | ||
431 | * | ||
432 | * %-ENOMEM - Insufficient amount of memory available. | ||
433 | * | ||
434 | * %-EINVAL - Invalid segment usage number. | ||
435 | */ | 436 | */ |
436 | int nilfs_sufile_get_segment_usage(struct inode *sufile, __u64 segnum, | 437 | int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum) |
437 | struct nilfs_segment_usage **sup, | ||
438 | struct buffer_head **bhp) | ||
439 | { | 438 | { |
440 | struct buffer_head *bh; | 439 | struct buffer_head *bh; |
441 | struct nilfs_segment_usage *su; | ||
442 | void *kaddr; | ||
443 | int ret; | 440 | int ret; |
444 | 441 | ||
445 | /* segnum is 0 origin */ | 442 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh); |
446 | if (segnum >= nilfs_sufile_get_nsegments(sufile)) | 443 | if (!ret) { |
447 | return -EINVAL; | 444 | nilfs_mdt_mark_buffer_dirty(bh); |
448 | down_write(&NILFS_MDT(sufile)->mi_sem); | 445 | nilfs_mdt_mark_dirty(sufile); |
449 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1, &bh); | ||
450 | if (ret < 0) | ||
451 | goto out_sem; | ||
452 | kaddr = kmap(bh->b_page); | ||
453 | su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr); | ||
454 | if (nilfs_segment_usage_error(su)) { | ||
455 | kunmap(bh->b_page); | ||
456 | brelse(bh); | 446 | brelse(bh); |
457 | ret = -EINVAL; | ||
458 | goto out_sem; | ||
459 | } | 447 | } |
460 | |||
461 | if (sup != NULL) | ||
462 | *sup = su; | ||
463 | *bhp = bh; | ||
464 | |||
465 | out_sem: | ||
466 | up_write(&NILFS_MDT(sufile)->mi_sem); | ||
467 | return ret; | 448 | return ret; |
468 | } | 449 | } |
469 | 450 | ||
470 | /** | 451 | /** |
471 | * nilfs_sufile_put_segment_usage - put a segment usage | 452 | * nilfs_sufile_set_segment_usage - set usage of a segment |
472 | * @sufile: inode of segment usage file | 453 | * @sufile: inode of segment usage file |
473 | * @segnum: segment number | 454 | * @segnum: segment number |
474 | * @bh: buffer head | 455 | * @nblocks: number of live blocks in the segment |
475 | * | 456 | * @modtime: modification time (option) |
476 | * Description: nilfs_sufile_put_segment_usage() releases the segment usage | ||
477 | * specified by @segnum. @bh must be the buffer head which have been returned | ||
478 | * by a previous call to nilfs_sufile_get_segment_usage() with @segnum. | ||
479 | */ | 457 | */ |
480 | void nilfs_sufile_put_segment_usage(struct inode *sufile, __u64 segnum, | 458 | int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, |
481 | struct buffer_head *bh) | 459 | unsigned long nblocks, time_t modtime) |
482 | { | 460 | { |
483 | kunmap(bh->b_page); | 461 | struct buffer_head *bh; |
462 | struct nilfs_segment_usage *su; | ||
463 | void *kaddr; | ||
464 | int ret; | ||
465 | |||
466 | down_write(&NILFS_MDT(sufile)->mi_sem); | ||
467 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh); | ||
468 | if (ret < 0) | ||
469 | goto out_sem; | ||
470 | |||
471 | kaddr = kmap_atomic(bh->b_page, KM_USER0); | ||
472 | su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr); | ||
473 | WARN_ON(nilfs_segment_usage_error(su)); | ||
474 | if (modtime) | ||
475 | su->su_lastmod = cpu_to_le64(modtime); | ||
476 | su->su_nblocks = cpu_to_le32(nblocks); | ||
477 | kunmap_atomic(kaddr, KM_USER0); | ||
478 | |||
479 | nilfs_mdt_mark_buffer_dirty(bh); | ||
480 | nilfs_mdt_mark_dirty(sufile); | ||
484 | brelse(bh); | 481 | brelse(bh); |
482 | |||
483 | out_sem: | ||
484 | up_write(&NILFS_MDT(sufile)->mi_sem); | ||
485 | return ret; | ||
485 | } | 486 | } |
486 | 487 | ||
487 | /** | 488 | /** |
@@ -515,7 +516,7 @@ int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat) | |||
515 | goto out_sem; | 516 | goto out_sem; |
516 | 517 | ||
517 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); | 518 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); |
518 | header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr); | 519 | header = kaddr + bh_offset(header_bh); |
519 | sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile); | 520 | sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile); |
520 | sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs); | 521 | sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs); |
521 | sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs); | 522 | sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs); |
@@ -532,33 +533,6 @@ int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat) | |||
532 | return ret; | 533 | return ret; |
533 | } | 534 | } |
534 | 535 | ||
535 | /** | ||
536 | * nilfs_sufile_get_ncleansegs - get the number of clean segments | ||
537 | * @sufile: inode of segment usage file | ||
538 | * @nsegsp: pointer to the number of clean segments | ||
539 | * | ||
540 | * Description: nilfs_sufile_get_ncleansegs() acquires the number of clean | ||
541 | * segments. | ||
542 | * | ||
543 | * Return Value: On success, 0 is returned and the number of clean segments is | ||
544 | * stored in the place pointed by @nsegsp. On error, one of the following | ||
545 | * negative error codes is returned. | ||
546 | * | ||
547 | * %-EIO - I/O error. | ||
548 | * | ||
549 | * %-ENOMEM - Insufficient amount of memory available. | ||
550 | */ | ||
551 | int nilfs_sufile_get_ncleansegs(struct inode *sufile, unsigned long *nsegsp) | ||
552 | { | ||
553 | struct nilfs_sustat sustat; | ||
554 | int ret; | ||
555 | |||
556 | ret = nilfs_sufile_get_stat(sufile, &sustat); | ||
557 | if (ret == 0) | ||
558 | *nsegsp = sustat.ss_ncleansegs; | ||
559 | return ret; | ||
560 | } | ||
561 | |||
562 | void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, | 536 | void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, |
563 | struct buffer_head *header_bh, | 537 | struct buffer_head *header_bh, |
564 | struct buffer_head *su_bh) | 538 | struct buffer_head *su_bh) |
@@ -577,8 +551,10 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, | |||
577 | nilfs_segment_usage_set_error(su); | 551 | nilfs_segment_usage_set_error(su); |
578 | kunmap_atomic(kaddr, KM_USER0); | 552 | kunmap_atomic(kaddr, KM_USER0); |
579 | 553 | ||
580 | if (suclean) | 554 | if (suclean) { |
581 | nilfs_sufile_mod_counter(header_bh, -1, 0); | 555 | nilfs_sufile_mod_counter(header_bh, -1, 0); |
556 | NILFS_SUI(sufile)->ncleansegs--; | ||
557 | } | ||
582 | nilfs_mdt_mark_buffer_dirty(su_bh); | 558 | nilfs_mdt_mark_buffer_dirty(su_bh); |
583 | nilfs_mdt_mark_dirty(sufile); | 559 | nilfs_mdt_mark_dirty(sufile); |
584 | } | 560 | } |
@@ -657,3 +633,48 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, | |||
657 | up_read(&NILFS_MDT(sufile)->mi_sem); | 633 | up_read(&NILFS_MDT(sufile)->mi_sem); |
658 | return ret; | 634 | return ret; |
659 | } | 635 | } |
636 | |||
637 | /** | ||
638 | * nilfs_sufile_read - read sufile inode | ||
639 | * @sufile: sufile inode | ||
640 | * @raw_inode: on-disk sufile inode | ||
641 | */ | ||
642 | int nilfs_sufile_read(struct inode *sufile, struct nilfs_inode *raw_inode) | ||
643 | { | ||
644 | struct nilfs_sufile_info *sui = NILFS_SUI(sufile); | ||
645 | struct buffer_head *header_bh; | ||
646 | struct nilfs_sufile_header *header; | ||
647 | void *kaddr; | ||
648 | int ret; | ||
649 | |||
650 | ret = nilfs_read_inode_common(sufile, raw_inode); | ||
651 | if (ret < 0) | ||
652 | return ret; | ||
653 | |||
654 | ret = nilfs_sufile_get_header_block(sufile, &header_bh); | ||
655 | if (!ret) { | ||
656 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); | ||
657 | header = kaddr + bh_offset(header_bh); | ||
658 | sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs); | ||
659 | kunmap_atomic(kaddr, KM_USER0); | ||
660 | brelse(header_bh); | ||
661 | } | ||
662 | return ret; | ||
663 | } | ||
664 | |||
665 | /** | ||
666 | * nilfs_sufile_new - create sufile | ||
667 | * @nilfs: nilfs object | ||
668 | * @susize: size of a segment usage entry | ||
669 | */ | ||
670 | struct inode *nilfs_sufile_new(struct the_nilfs *nilfs, size_t susize) | ||
671 | { | ||
672 | struct inode *sufile; | ||
673 | |||
674 | sufile = nilfs_mdt_new(nilfs, NULL, NILFS_SUFILE_INO, | ||
675 | sizeof(struct nilfs_sufile_info)); | ||
676 | if (sufile) | ||
677 | nilfs_mdt_set_entry_size(sufile, susize, | ||
678 | sizeof(struct nilfs_sufile_header)); | ||
679 | return sufile; | ||
680 | } | ||