diff options
| -rw-r--r-- | Documentation/filesystems/nilfs2.txt | 3 | ||||
| -rw-r--r-- | fs/nilfs2/dat.c | 3 | ||||
| -rw-r--r-- | fs/nilfs2/ioctl.c | 66 | ||||
| -rw-r--r-- | fs/nilfs2/recovery.c | 41 | ||||
| -rw-r--r-- | fs/nilfs2/segbuf.c | 18 | ||||
| -rw-r--r-- | fs/nilfs2/segbuf.h | 5 | ||||
| -rw-r--r-- | fs/nilfs2/segment.c | 120 | ||||
| -rw-r--r-- | fs/nilfs2/segment.h | 2 | ||||
| -rw-r--r-- | fs/nilfs2/super.c | 15 | ||||
| -rw-r--r-- | fs/nilfs2/the_nilfs.c | 38 | ||||
| -rw-r--r-- | fs/nilfs2/the_nilfs.h | 3 | ||||
| -rw-r--r-- | include/linux/nilfs2_fs.h | 1 |
12 files changed, 199 insertions, 116 deletions
diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt index 839efd8a8a8c..cf6d0d85ca82 100644 --- a/Documentation/filesystems/nilfs2.txt +++ b/Documentation/filesystems/nilfs2.txt | |||
| @@ -74,6 +74,9 @@ norecovery Disable recovery of the filesystem on mount. | |||
| 74 | This disables every write access on the device for | 74 | This disables every write access on the device for |
| 75 | read-only mounts or snapshots. This option will fail | 75 | read-only mounts or snapshots. This option will fail |
| 76 | for r/w mounts on an unclean volume. | 76 | for r/w mounts on an unclean volume. |
| 77 | discard Issue discard/TRIM commands to the underlying block | ||
| 78 | device when blocks are freed. This is useful for SSD | ||
| 79 | devices and sparse/thinly-provisioned LUNs. | ||
| 77 | 80 | ||
| 78 | NILFS2 usage | 81 | NILFS2 usage |
| 79 | ============ | 82 | ============ |
diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 187dd07ba86c..9d1e5de91afb 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c | |||
| @@ -388,8 +388,7 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) | |||
| 388 | ret = -ENOENT; | 388 | ret = -ENOENT; |
| 389 | goto out; | 389 | goto out; |
| 390 | } | 390 | } |
| 391 | if (blocknrp != NULL) | 391 | *blocknrp = blocknr; |
| 392 | *blocknrp = blocknr; | ||
| 393 | 392 | ||
| 394 | out: | 393 | out: |
| 395 | kunmap_atomic(kaddr, KM_USER0); | 394 | kunmap_atomic(kaddr, KM_USER0); |
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index d6b2b83de363..313d0a21da48 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/capability.h> /* capable() */ | 26 | #include <linux/capability.h> /* capable() */ |
| 27 | #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ | 27 | #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ |
| 28 | #include <linux/vmalloc.h> | 28 | #include <linux/vmalloc.h> |
| 29 | #include <linux/mount.h> /* mnt_want_write(), mnt_drop_write() */ | ||
| 29 | #include <linux/nilfs2_fs.h> | 30 | #include <linux/nilfs2_fs.h> |
| 30 | #include "nilfs.h" | 31 | #include "nilfs.h" |
| 31 | #include "segment.h" | 32 | #include "segment.h" |
| @@ -107,20 +108,28 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, | |||
| 107 | 108 | ||
| 108 | if (!capable(CAP_SYS_ADMIN)) | 109 | if (!capable(CAP_SYS_ADMIN)) |
| 109 | return -EPERM; | 110 | return -EPERM; |
| 111 | |||
| 112 | ret = mnt_want_write(filp->f_path.mnt); | ||
| 113 | if (ret) | ||
| 114 | return ret; | ||
| 115 | |||
| 116 | ret = -EFAULT; | ||
| 110 | if (copy_from_user(&cpmode, argp, sizeof(cpmode))) | 117 | if (copy_from_user(&cpmode, argp, sizeof(cpmode))) |
| 111 | return -EFAULT; | 118 | goto out; |
| 112 | 119 | ||
| 113 | mutex_lock(&nilfs->ns_mount_mutex); | 120 | mutex_lock(&nilfs->ns_mount_mutex); |
| 121 | |||
| 114 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 122 | nilfs_transaction_begin(inode->i_sb, &ti, 0); |
| 115 | ret = nilfs_cpfile_change_cpmode( | 123 | ret = nilfs_cpfile_change_cpmode( |
| 116 | cpfile, cpmode.cm_cno, cpmode.cm_mode); | 124 | cpfile, cpmode.cm_cno, cpmode.cm_mode); |
| 117 | if (unlikely(ret < 0)) { | 125 | if (unlikely(ret < 0)) |
| 118 | nilfs_transaction_abort(inode->i_sb); | 126 | nilfs_transaction_abort(inode->i_sb); |
| 119 | mutex_unlock(&nilfs->ns_mount_mutex); | 127 | else |
| 120 | return ret; | 128 | nilfs_transaction_commit(inode->i_sb); /* never fails */ |
| 121 | } | 129 | |
| 122 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | ||
| 123 | mutex_unlock(&nilfs->ns_mount_mutex); | 130 | mutex_unlock(&nilfs->ns_mount_mutex); |
| 131 | out: | ||
| 132 | mnt_drop_write(filp->f_path.mnt); | ||
| 124 | return ret; | 133 | return ret; |
| 125 | } | 134 | } |
| 126 | 135 | ||
| @@ -135,16 +144,23 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, | |||
| 135 | 144 | ||
| 136 | if (!capable(CAP_SYS_ADMIN)) | 145 | if (!capable(CAP_SYS_ADMIN)) |
| 137 | return -EPERM; | 146 | return -EPERM; |
| 147 | |||
| 148 | ret = mnt_want_write(filp->f_path.mnt); | ||
| 149 | if (ret) | ||
| 150 | return ret; | ||
| 151 | |||
| 152 | ret = -EFAULT; | ||
| 138 | if (copy_from_user(&cno, argp, sizeof(cno))) | 153 | if (copy_from_user(&cno, argp, sizeof(cno))) |
| 139 | return -EFAULT; | 154 | goto out; |
| 140 | 155 | ||
| 141 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 156 | nilfs_transaction_begin(inode->i_sb, &ti, 0); |
| 142 | ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); | 157 | ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); |
| 143 | if (unlikely(ret < 0)) { | 158 | if (unlikely(ret < 0)) |
| 144 | nilfs_transaction_abort(inode->i_sb); | 159 | nilfs_transaction_abort(inode->i_sb); |
| 145 | return ret; | 160 | else |
| 146 | } | 161 | nilfs_transaction_commit(inode->i_sb); /* never fails */ |
| 147 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | 162 | out: |
| 163 | mnt_drop_write(filp->f_path.mnt); | ||
| 148 | return ret; | 164 | return ret; |
| 149 | } | 165 | } |
| 150 | 166 | ||
| @@ -496,12 +512,19 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
| 496 | if (!capable(CAP_SYS_ADMIN)) | 512 | if (!capable(CAP_SYS_ADMIN)) |
| 497 | return -EPERM; | 513 | return -EPERM; |
| 498 | 514 | ||
| 515 | ret = mnt_want_write(filp->f_path.mnt); | ||
| 516 | if (ret) | ||
| 517 | return ret; | ||
| 518 | |||
| 519 | ret = -EFAULT; | ||
| 499 | if (copy_from_user(argv, argp, sizeof(argv))) | 520 | if (copy_from_user(argv, argp, sizeof(argv))) |
| 500 | return -EFAULT; | 521 | goto out; |
| 501 | 522 | ||
| 523 | ret = -EINVAL; | ||
| 502 | nsegs = argv[4].v_nmembs; | 524 | nsegs = argv[4].v_nmembs; |
| 503 | if (argv[4].v_size != argsz[4]) | 525 | if (argv[4].v_size != argsz[4]) |
| 504 | return -EINVAL; | 526 | goto out; |
| 527 | |||
| 505 | /* | 528 | /* |
| 506 | * argv[4] points to segment numbers this ioctl cleans. We | 529 | * argv[4] points to segment numbers this ioctl cleans. We |
| 507 | * use kmalloc() for its buffer because memory used for the | 530 | * use kmalloc() for its buffer because memory used for the |
| @@ -509,9 +532,10 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
| 509 | */ | 532 | */ |
| 510 | kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, | 533 | kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, |
| 511 | nsegs * sizeof(__u64)); | 534 | nsegs * sizeof(__u64)); |
| 512 | if (IS_ERR(kbufs[4])) | 535 | if (IS_ERR(kbufs[4])) { |
| 513 | return PTR_ERR(kbufs[4]); | 536 | ret = PTR_ERR(kbufs[4]); |
| 514 | 537 | goto out; | |
| 538 | } | ||
| 515 | nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | 539 | nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
| 516 | 540 | ||
| 517 | for (n = 0; n < 4; n++) { | 541 | for (n = 0; n < 4; n++) { |
| @@ -563,10 +587,12 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
| 563 | nilfs_remove_all_gcinode(nilfs); | 587 | nilfs_remove_all_gcinode(nilfs); |
| 564 | clear_nilfs_gc_running(nilfs); | 588 | clear_nilfs_gc_running(nilfs); |
| 565 | 589 | ||
| 566 | out_free: | 590 | out_free: |
| 567 | while (--n >= 0) | 591 | while (--n >= 0) |
| 568 | vfree(kbufs[n]); | 592 | vfree(kbufs[n]); |
| 569 | kfree(kbufs[4]); | 593 | kfree(kbufs[4]); |
| 594 | out: | ||
| 595 | mnt_drop_write(filp->f_path.mnt); | ||
| 570 | return ret; | 596 | return ret; |
| 571 | } | 597 | } |
| 572 | 598 | ||
| @@ -575,13 +601,17 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp, | |||
| 575 | { | 601 | { |
| 576 | __u64 cno; | 602 | __u64 cno; |
| 577 | int ret; | 603 | int ret; |
| 604 | struct the_nilfs *nilfs; | ||
| 578 | 605 | ||
| 579 | ret = nilfs_construct_segment(inode->i_sb); | 606 | ret = nilfs_construct_segment(inode->i_sb); |
| 580 | if (ret < 0) | 607 | if (ret < 0) |
| 581 | return ret; | 608 | return ret; |
| 582 | 609 | ||
| 583 | if (argp != NULL) { | 610 | if (argp != NULL) { |
| 584 | cno = NILFS_SB(inode->i_sb)->s_nilfs->ns_cno - 1; | 611 | nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
| 612 | down_read(&nilfs->ns_segctor_sem); | ||
| 613 | cno = nilfs->ns_cno - 1; | ||
| 614 | up_read(&nilfs->ns_segctor_sem); | ||
| 585 | if (copy_to_user(argp, &cno, sizeof(cno))) | 615 | if (copy_to_user(argp, &cno, sizeof(cno))) |
| 586 | return -EFAULT; | 616 | return -EFAULT; |
| 587 | } | 617 | } |
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index c9c96c7825dc..017bedc761a0 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c | |||
| @@ -39,7 +39,6 @@ enum { | |||
| 39 | NILFS_SEG_FAIL_IO, | 39 | NILFS_SEG_FAIL_IO, |
| 40 | NILFS_SEG_FAIL_MAGIC, | 40 | NILFS_SEG_FAIL_MAGIC, |
| 41 | NILFS_SEG_FAIL_SEQ, | 41 | NILFS_SEG_FAIL_SEQ, |
| 42 | NILFS_SEG_FAIL_CHECKSUM_SEGSUM, | ||
| 43 | NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT, | 42 | NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT, |
| 44 | NILFS_SEG_FAIL_CHECKSUM_FULL, | 43 | NILFS_SEG_FAIL_CHECKSUM_FULL, |
| 45 | NILFS_SEG_FAIL_CONSISTENCY, | 44 | NILFS_SEG_FAIL_CONSISTENCY, |
| @@ -71,10 +70,6 @@ static int nilfs_warn_segment_error(int err) | |||
| 71 | printk(KERN_WARNING | 70 | printk(KERN_WARNING |
| 72 | "NILFS warning: Sequence number mismatch\n"); | 71 | "NILFS warning: Sequence number mismatch\n"); |
| 73 | break; | 72 | break; |
| 74 | case NILFS_SEG_FAIL_CHECKSUM_SEGSUM: | ||
| 75 | printk(KERN_WARNING | ||
| 76 | "NILFS warning: Checksum error in segment summary\n"); | ||
| 77 | break; | ||
| 78 | case NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT: | 73 | case NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT: |
| 79 | printk(KERN_WARNING | 74 | printk(KERN_WARNING |
| 80 | "NILFS warning: Checksum error in super root\n"); | 75 | "NILFS warning: Checksum error in super root\n"); |
| @@ -206,19 +201,15 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block, | |||
| 206 | * @pseg_start: start disk block number of partial segment | 201 | * @pseg_start: start disk block number of partial segment |
| 207 | * @seg_seq: sequence number requested | 202 | * @seg_seq: sequence number requested |
| 208 | * @ssi: pointer to nilfs_segsum_info struct to store information | 203 | * @ssi: pointer to nilfs_segsum_info struct to store information |
| 209 | * @full_check: full check flag | ||
| 210 | * (0: only checks segment summary CRC, 1: data CRC) | ||
| 211 | */ | 204 | */ |
| 212 | static int | 205 | static int |
| 213 | load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start, | 206 | load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start, |
| 214 | u64 seg_seq, struct nilfs_segsum_info *ssi, | 207 | u64 seg_seq, struct nilfs_segsum_info *ssi) |
| 215 | int full_check) | ||
| 216 | { | 208 | { |
| 217 | struct buffer_head *bh_sum; | 209 | struct buffer_head *bh_sum; |
| 218 | struct nilfs_segment_summary *sum; | 210 | struct nilfs_segment_summary *sum; |
| 219 | unsigned long offset, nblock; | 211 | unsigned long nblock; |
| 220 | u64 check_bytes; | 212 | u32 crc; |
| 221 | u32 crc, crc_sum; | ||
| 222 | int ret = NILFS_SEG_FAIL_IO; | 213 | int ret = NILFS_SEG_FAIL_IO; |
| 223 | 214 | ||
| 224 | bh_sum = sb_bread(sbi->s_super, pseg_start); | 215 | bh_sum = sb_bread(sbi->s_super, pseg_start); |
| @@ -237,34 +228,24 @@ load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start, | |||
| 237 | ret = NILFS_SEG_FAIL_SEQ; | 228 | ret = NILFS_SEG_FAIL_SEQ; |
| 238 | goto failed; | 229 | goto failed; |
| 239 | } | 230 | } |
| 240 | if (full_check) { | ||
| 241 | offset = sizeof(sum->ss_datasum); | ||
| 242 | check_bytes = | ||
| 243 | ((u64)ssi->nblocks << sbi->s_super->s_blocksize_bits); | ||
| 244 | nblock = ssi->nblocks; | ||
| 245 | crc_sum = le32_to_cpu(sum->ss_datasum); | ||
| 246 | ret = NILFS_SEG_FAIL_CHECKSUM_FULL; | ||
| 247 | } else { /* only checks segment summary */ | ||
| 248 | offset = sizeof(sum->ss_datasum) + sizeof(sum->ss_sumsum); | ||
| 249 | check_bytes = ssi->sumbytes; | ||
| 250 | nblock = ssi->nsumblk; | ||
| 251 | crc_sum = le32_to_cpu(sum->ss_sumsum); | ||
| 252 | ret = NILFS_SEG_FAIL_CHECKSUM_SEGSUM; | ||
| 253 | } | ||
| 254 | 231 | ||
| 232 | nblock = ssi->nblocks; | ||
| 255 | if (unlikely(nblock == 0 || | 233 | if (unlikely(nblock == 0 || |
| 256 | nblock > sbi->s_nilfs->ns_blocks_per_segment)) { | 234 | nblock > sbi->s_nilfs->ns_blocks_per_segment)) { |
| 257 | /* This limits the number of blocks read in the CRC check */ | 235 | /* This limits the number of blocks read in the CRC check */ |
| 258 | ret = NILFS_SEG_FAIL_CONSISTENCY; | 236 | ret = NILFS_SEG_FAIL_CONSISTENCY; |
| 259 | goto failed; | 237 | goto failed; |
| 260 | } | 238 | } |
| 261 | if (calc_crc_cont(sbi, bh_sum, &crc, offset, check_bytes, | 239 | if (calc_crc_cont(sbi, bh_sum, &crc, sizeof(sum->ss_datasum), |
| 240 | ((u64)nblock << sbi->s_super->s_blocksize_bits), | ||
| 262 | pseg_start, nblock)) { | 241 | pseg_start, nblock)) { |
| 263 | ret = NILFS_SEG_FAIL_IO; | 242 | ret = NILFS_SEG_FAIL_IO; |
| 264 | goto failed; | 243 | goto failed; |
| 265 | } | 244 | } |
| 266 | if (crc == crc_sum) | 245 | if (crc == le32_to_cpu(sum->ss_datasum)) |
| 267 | ret = 0; | 246 | ret = 0; |
| 247 | else | ||
| 248 | ret = NILFS_SEG_FAIL_CHECKSUM_FULL; | ||
| 268 | failed: | 249 | failed: |
| 269 | brelse(bh_sum); | 250 | brelse(bh_sum); |
| 270 | out: | 251 | out: |
| @@ -598,7 +579,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs, | |||
| 598 | 579 | ||
| 599 | while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) { | 580 | while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) { |
| 600 | 581 | ||
| 601 | ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi, 1); | 582 | ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi); |
| 602 | if (ret) { | 583 | if (ret) { |
| 603 | if (ret == NILFS_SEG_FAIL_IO) { | 584 | if (ret == NILFS_SEG_FAIL_IO) { |
| 604 | err = -EIO; | 585 | err = -EIO; |
| @@ -821,7 +802,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, | |||
| 821 | 802 | ||
| 822 | for (;;) { | 803 | for (;;) { |
| 823 | /* Load segment summary */ | 804 | /* Load segment summary */ |
| 824 | ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi, 1); | 805 | ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi); |
| 825 | if (ret) { | 806 | if (ret) { |
| 826 | if (ret == NILFS_SEG_FAIL_IO) | 807 | if (ret == NILFS_SEG_FAIL_IO) |
| 827 | goto failed; | 808 | goto failed; |
diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 645c78656aa0..ab56fe44e377 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c | |||
| @@ -40,6 +40,11 @@ struct nilfs_write_info { | |||
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| 42 | 42 | ||
| 43 | static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf, | ||
| 44 | struct the_nilfs *nilfs); | ||
| 45 | static int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf); | ||
| 46 | |||
| 47 | |||
| 43 | static struct kmem_cache *nilfs_segbuf_cachep; | 48 | static struct kmem_cache *nilfs_segbuf_cachep; |
| 44 | 49 | ||
| 45 | static void nilfs_segbuf_init_once(void *obj) | 50 | static void nilfs_segbuf_init_once(void *obj) |
| @@ -302,6 +307,19 @@ void nilfs_truncate_logs(struct list_head *logs, | |||
| 302 | } | 307 | } |
| 303 | } | 308 | } |
| 304 | 309 | ||
| 310 | int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs) | ||
| 311 | { | ||
| 312 | struct nilfs_segment_buffer *segbuf; | ||
| 313 | int ret = 0; | ||
| 314 | |||
| 315 | list_for_each_entry(segbuf, logs, sb_list) { | ||
| 316 | ret = nilfs_segbuf_write(segbuf, nilfs); | ||
| 317 | if (ret) | ||
| 318 | break; | ||
| 319 | } | ||
| 320 | return ret; | ||
| 321 | } | ||
| 322 | |||
| 305 | int nilfs_wait_on_logs(struct list_head *logs) | 323 | int nilfs_wait_on_logs(struct list_head *logs) |
| 306 | { | 324 | { |
| 307 | struct nilfs_segment_buffer *segbuf; | 325 | struct nilfs_segment_buffer *segbuf; |
diff --git a/fs/nilfs2/segbuf.h b/fs/nilfs2/segbuf.h index 6af1630fb401..94dfd3517bc0 100644 --- a/fs/nilfs2/segbuf.h +++ b/fs/nilfs2/segbuf.h | |||
| @@ -166,13 +166,10 @@ nilfs_segbuf_add_file_buffer(struct nilfs_segment_buffer *segbuf, | |||
| 166 | segbuf->sb_sum.nfileblk++; | 166 | segbuf->sb_sum.nfileblk++; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf, | ||
| 170 | struct the_nilfs *nilfs); | ||
| 171 | int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf); | ||
| 172 | |||
| 173 | void nilfs_clear_logs(struct list_head *logs); | 169 | void nilfs_clear_logs(struct list_head *logs); |
| 174 | void nilfs_truncate_logs(struct list_head *logs, | 170 | void nilfs_truncate_logs(struct list_head *logs, |
| 175 | struct nilfs_segment_buffer *last); | 171 | struct nilfs_segment_buffer *last); |
| 172 | int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs); | ||
| 176 | int nilfs_wait_on_logs(struct list_head *logs); | 173 | int nilfs_wait_on_logs(struct list_head *logs); |
| 177 | 174 | ||
| 178 | static inline void nilfs_destroy_logs(struct list_head *logs) | 175 | static inline void nilfs_destroy_logs(struct list_head *logs) |
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 105b508b47a8..ada2f1b947a3 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
| @@ -1764,14 +1764,9 @@ static int nilfs_segctor_prepare_write(struct nilfs_sc_info *sci, | |||
| 1764 | static int nilfs_segctor_write(struct nilfs_sc_info *sci, | 1764 | static int nilfs_segctor_write(struct nilfs_sc_info *sci, |
| 1765 | struct the_nilfs *nilfs) | 1765 | struct the_nilfs *nilfs) |
| 1766 | { | 1766 | { |
| 1767 | struct nilfs_segment_buffer *segbuf; | 1767 | int ret; |
| 1768 | int ret = 0; | ||
| 1769 | 1768 | ||
| 1770 | list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) { | 1769 | ret = nilfs_write_logs(&sci->sc_segbufs, nilfs); |
| 1771 | ret = nilfs_segbuf_write(segbuf, nilfs); | ||
| 1772 | if (ret) | ||
| 1773 | break; | ||
| 1774 | } | ||
| 1775 | list_splice_tail_init(&sci->sc_segbufs, &sci->sc_write_logs); | 1770 | list_splice_tail_init(&sci->sc_segbufs, &sci->sc_write_logs); |
| 1776 | return ret; | 1771 | return ret; |
| 1777 | } | 1772 | } |
| @@ -1937,8 +1932,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) | |||
| 1937 | { | 1932 | { |
| 1938 | struct nilfs_segment_buffer *segbuf; | 1933 | struct nilfs_segment_buffer *segbuf; |
| 1939 | struct page *bd_page = NULL, *fs_page = NULL; | 1934 | struct page *bd_page = NULL, *fs_page = NULL; |
| 1940 | struct nilfs_sb_info *sbi = sci->sc_sbi; | 1935 | struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs; |
| 1941 | struct the_nilfs *nilfs = sbi->s_nilfs; | ||
| 1942 | int update_sr = (sci->sc_super_root != NULL); | 1936 | int update_sr = (sci->sc_super_root != NULL); |
| 1943 | 1937 | ||
| 1944 | list_for_each_entry(segbuf, &sci->sc_write_logs, sb_list) { | 1938 | list_for_each_entry(segbuf, &sci->sc_write_logs, sb_list) { |
| @@ -2020,7 +2014,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) | |||
| 2020 | if (update_sr) { | 2014 | if (update_sr) { |
| 2021 | nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start, | 2015 | nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start, |
| 2022 | segbuf->sb_sum.seg_seq, nilfs->ns_cno++); | 2016 | segbuf->sb_sum.seg_seq, nilfs->ns_cno++); |
| 2023 | sbi->s_super->s_dirt = 1; | 2017 | set_nilfs_sb_dirty(nilfs); |
| 2024 | 2018 | ||
| 2025 | clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags); | 2019 | clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags); |
| 2026 | clear_bit(NILFS_SC_DIRTY, &sci->sc_flags); | 2020 | clear_bit(NILFS_SC_DIRTY, &sci->sc_flags); |
| @@ -2425,43 +2419,43 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode, | |||
| 2425 | return err; | 2419 | return err; |
| 2426 | } | 2420 | } |
| 2427 | 2421 | ||
| 2428 | struct nilfs_segctor_req { | ||
| 2429 | int mode; | ||
| 2430 | __u32 seq_accepted; | ||
| 2431 | int sc_err; /* construction failure */ | ||
| 2432 | int sb_err; /* super block writeback failure */ | ||
| 2433 | }; | ||
| 2434 | |||
| 2435 | #define FLUSH_FILE_BIT (0x1) /* data file only */ | 2422 | #define FLUSH_FILE_BIT (0x1) /* data file only */ |
| 2436 | #define FLUSH_DAT_BIT (1 << NILFS_DAT_INO) /* DAT only */ | 2423 | #define FLUSH_DAT_BIT (1 << NILFS_DAT_INO) /* DAT only */ |
| 2437 | 2424 | ||
| 2438 | static void nilfs_segctor_accept(struct nilfs_sc_info *sci, | 2425 | /** |
| 2439 | struct nilfs_segctor_req *req) | 2426 | * nilfs_segctor_accept - record accepted sequence count of log-write requests |
| 2427 | * @sci: segment constructor object | ||
| 2428 | */ | ||
| 2429 | static void nilfs_segctor_accept(struct nilfs_sc_info *sci) | ||
| 2440 | { | 2430 | { |
| 2441 | req->sc_err = req->sb_err = 0; | ||
| 2442 | spin_lock(&sci->sc_state_lock); | 2431 | spin_lock(&sci->sc_state_lock); |
| 2443 | req->seq_accepted = sci->sc_seq_request; | 2432 | sci->sc_seq_accepted = sci->sc_seq_request; |
| 2444 | spin_unlock(&sci->sc_state_lock); | 2433 | spin_unlock(&sci->sc_state_lock); |
| 2445 | 2434 | ||
| 2446 | if (sci->sc_timer) | 2435 | if (sci->sc_timer) |
| 2447 | del_timer_sync(sci->sc_timer); | 2436 | del_timer_sync(sci->sc_timer); |
| 2448 | } | 2437 | } |
| 2449 | 2438 | ||
| 2450 | static void nilfs_segctor_notify(struct nilfs_sc_info *sci, | 2439 | /** |
| 2451 | struct nilfs_segctor_req *req) | 2440 | * nilfs_segctor_notify - notify the result of request to caller threads |
| 2441 | * @sci: segment constructor object | ||
| 2442 | * @mode: mode of log forming | ||
| 2443 | * @err: error code to be notified | ||
| 2444 | */ | ||
| 2445 | static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err) | ||
| 2452 | { | 2446 | { |
| 2453 | /* Clear requests (even when the construction failed) */ | 2447 | /* Clear requests (even when the construction failed) */ |
| 2454 | spin_lock(&sci->sc_state_lock); | 2448 | spin_lock(&sci->sc_state_lock); |
| 2455 | 2449 | ||
| 2456 | if (req->mode == SC_LSEG_SR) { | 2450 | if (mode == SC_LSEG_SR) { |
| 2457 | sci->sc_state &= ~NILFS_SEGCTOR_COMMIT; | 2451 | sci->sc_state &= ~NILFS_SEGCTOR_COMMIT; |
| 2458 | sci->sc_seq_done = req->seq_accepted; | 2452 | sci->sc_seq_done = sci->sc_seq_accepted; |
| 2459 | nilfs_segctor_wakeup(sci, req->sc_err ? : req->sb_err); | 2453 | nilfs_segctor_wakeup(sci, err); |
| 2460 | sci->sc_flush_request = 0; | 2454 | sci->sc_flush_request = 0; |
| 2461 | } else { | 2455 | } else { |
| 2462 | if (req->mode == SC_FLUSH_FILE) | 2456 | if (mode == SC_FLUSH_FILE) |
| 2463 | sci->sc_flush_request &= ~FLUSH_FILE_BIT; | 2457 | sci->sc_flush_request &= ~FLUSH_FILE_BIT; |
| 2464 | else if (req->mode == SC_FLUSH_DAT) | 2458 | else if (mode == SC_FLUSH_DAT) |
| 2465 | sci->sc_flush_request &= ~FLUSH_DAT_BIT; | 2459 | sci->sc_flush_request &= ~FLUSH_DAT_BIT; |
| 2466 | 2460 | ||
| 2467 | /* re-enable timer if checkpoint creation was not done */ | 2461 | /* re-enable timer if checkpoint creation was not done */ |
| @@ -2472,30 +2466,37 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci, | |||
| 2472 | spin_unlock(&sci->sc_state_lock); | 2466 | spin_unlock(&sci->sc_state_lock); |
| 2473 | } | 2467 | } |
| 2474 | 2468 | ||
| 2475 | static int nilfs_segctor_construct(struct nilfs_sc_info *sci, | 2469 | /** |
| 2476 | struct nilfs_segctor_req *req) | 2470 | * nilfs_segctor_construct - form logs and write them to disk |
| 2471 | * @sci: segment constructor object | ||
| 2472 | * @mode: mode of log forming | ||
| 2473 | */ | ||
| 2474 | static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode) | ||
| 2477 | { | 2475 | { |
| 2478 | struct nilfs_sb_info *sbi = sci->sc_sbi; | 2476 | struct nilfs_sb_info *sbi = sci->sc_sbi; |
| 2479 | struct the_nilfs *nilfs = sbi->s_nilfs; | 2477 | struct the_nilfs *nilfs = sbi->s_nilfs; |
| 2480 | int err = 0; | 2478 | int err = 0; |
| 2481 | 2479 | ||
| 2480 | nilfs_segctor_accept(sci); | ||
| 2481 | |||
| 2482 | if (nilfs_discontinued(nilfs)) | 2482 | if (nilfs_discontinued(nilfs)) |
| 2483 | req->mode = SC_LSEG_SR; | 2483 | mode = SC_LSEG_SR; |
| 2484 | if (!nilfs_segctor_confirm(sci)) { | 2484 | if (!nilfs_segctor_confirm(sci)) |
| 2485 | err = nilfs_segctor_do_construct(sci, req->mode); | 2485 | err = nilfs_segctor_do_construct(sci, mode); |
| 2486 | req->sc_err = err; | 2486 | |
| 2487 | } | ||
| 2488 | if (likely(!err)) { | 2487 | if (likely(!err)) { |
| 2489 | if (req->mode != SC_FLUSH_DAT) | 2488 | if (mode != SC_FLUSH_DAT) |
| 2490 | atomic_set(&nilfs->ns_ndirtyblks, 0); | 2489 | atomic_set(&nilfs->ns_ndirtyblks, 0); |
| 2491 | if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) && | 2490 | if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) && |
| 2492 | nilfs_discontinued(nilfs)) { | 2491 | nilfs_discontinued(nilfs)) { |
| 2493 | down_write(&nilfs->ns_sem); | 2492 | down_write(&nilfs->ns_sem); |
| 2494 | req->sb_err = nilfs_commit_super(sbi, | 2493 | err = nilfs_commit_super( |
| 2495 | nilfs_altsb_need_update(nilfs)); | 2494 | sbi, nilfs_altsb_need_update(nilfs)); |
| 2496 | up_write(&nilfs->ns_sem); | 2495 | up_write(&nilfs->ns_sem); |
| 2497 | } | 2496 | } |
| 2498 | } | 2497 | } |
| 2498 | |||
| 2499 | nilfs_segctor_notify(sci, mode, err); | ||
| 2499 | return err; | 2500 | return err; |
| 2500 | } | 2501 | } |
| 2501 | 2502 | ||
| @@ -2526,7 +2527,6 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, | |||
| 2526 | struct nilfs_sc_info *sci = NILFS_SC(sbi); | 2527 | struct nilfs_sc_info *sci = NILFS_SC(sbi); |
| 2527 | struct the_nilfs *nilfs = sbi->s_nilfs; | 2528 | struct the_nilfs *nilfs = sbi->s_nilfs; |
| 2528 | struct nilfs_transaction_info ti; | 2529 | struct nilfs_transaction_info ti; |
| 2529 | struct nilfs_segctor_req req = { .mode = SC_LSEG_SR }; | ||
| 2530 | int err; | 2530 | int err; |
| 2531 | 2531 | ||
| 2532 | if (unlikely(!sci)) | 2532 | if (unlikely(!sci)) |
| @@ -2547,10 +2547,8 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, | |||
| 2547 | list_splice_tail_init(&nilfs->ns_gc_inodes, &sci->sc_gc_inodes); | 2547 | list_splice_tail_init(&nilfs->ns_gc_inodes, &sci->sc_gc_inodes); |
| 2548 | 2548 | ||
| 2549 | for (;;) { | 2549 | for (;;) { |
| 2550 | nilfs_segctor_accept(sci, &req); | 2550 | err = nilfs_segctor_construct(sci, SC_LSEG_SR); |
| 2551 | err = nilfs_segctor_construct(sci, &req); | ||
| 2552 | nilfs_remove_written_gcinodes(nilfs, &sci->sc_gc_inodes); | 2551 | nilfs_remove_written_gcinodes(nilfs, &sci->sc_gc_inodes); |
| 2553 | nilfs_segctor_notify(sci, &req); | ||
| 2554 | 2552 | ||
| 2555 | if (likely(!err)) | 2553 | if (likely(!err)) |
| 2556 | break; | 2554 | break; |
| @@ -2560,6 +2558,16 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, | |||
| 2560 | set_current_state(TASK_INTERRUPTIBLE); | 2558 | set_current_state(TASK_INTERRUPTIBLE); |
| 2561 | schedule_timeout(sci->sc_interval); | 2559 | schedule_timeout(sci->sc_interval); |
| 2562 | } | 2560 | } |
| 2561 | if (nilfs_test_opt(sbi, DISCARD)) { | ||
| 2562 | int ret = nilfs_discard_segments(nilfs, sci->sc_freesegs, | ||
| 2563 | sci->sc_nfreesegs); | ||
| 2564 | if (ret) { | ||
| 2565 | printk(KERN_WARNING | ||
| 2566 | "NILFS warning: error %d on discard request, " | ||
| 2567 | "turning discards off for the device\n", ret); | ||
| 2568 | nilfs_clear_opt(sbi, DISCARD); | ||
| 2569 | } | ||
| 2570 | } | ||
| 2563 | 2571 | ||
| 2564 | out_unlock: | 2572 | out_unlock: |
| 2565 | sci->sc_freesegs = NULL; | 2573 | sci->sc_freesegs = NULL; |
| @@ -2573,13 +2581,9 @@ static void nilfs_segctor_thread_construct(struct nilfs_sc_info *sci, int mode) | |||
| 2573 | { | 2581 | { |
| 2574 | struct nilfs_sb_info *sbi = sci->sc_sbi; | 2582 | struct nilfs_sb_info *sbi = sci->sc_sbi; |
| 2575 | struct nilfs_transaction_info ti; | 2583 | struct nilfs_transaction_info ti; |
| 2576 | struct nilfs_segctor_req req = { .mode = mode }; | ||
| 2577 | 2584 | ||
| 2578 | nilfs_transaction_lock(sbi, &ti, 0); | 2585 | nilfs_transaction_lock(sbi, &ti, 0); |
| 2579 | 2586 | nilfs_segctor_construct(sci, mode); | |
| 2580 | nilfs_segctor_accept(sci, &req); | ||
| 2581 | nilfs_segctor_construct(sci, &req); | ||
| 2582 | nilfs_segctor_notify(sci, &req); | ||
| 2583 | 2587 | ||
| 2584 | /* | 2588 | /* |
| 2585 | * Unclosed segment should be retried. We do this using sc_timer. | 2589 | * Unclosed segment should be retried. We do this using sc_timer. |
| @@ -2635,6 +2639,7 @@ static int nilfs_segctor_flush_mode(struct nilfs_sc_info *sci) | |||
| 2635 | static int nilfs_segctor_thread(void *arg) | 2639 | static int nilfs_segctor_thread(void *arg) |
| 2636 | { | 2640 | { |
| 2637 | struct nilfs_sc_info *sci = (struct nilfs_sc_info *)arg; | 2641 | struct nilfs_sc_info *sci = (struct nilfs_sc_info *)arg; |
| 2642 | struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs; | ||
| 2638 | struct timer_list timer; | 2643 | struct timer_list timer; |
| 2639 | int timeout = 0; | 2644 | int timeout = 0; |
| 2640 | 2645 | ||
| @@ -2680,7 +2685,6 @@ static int nilfs_segctor_thread(void *arg) | |||
| 2680 | } else { | 2685 | } else { |
| 2681 | DEFINE_WAIT(wait); | 2686 | DEFINE_WAIT(wait); |
| 2682 | int should_sleep = 1; | 2687 | int should_sleep = 1; |
| 2683 | struct the_nilfs *nilfs; | ||
| 2684 | 2688 | ||
| 2685 | prepare_to_wait(&sci->sc_wait_daemon, &wait, | 2689 | prepare_to_wait(&sci->sc_wait_daemon, &wait, |
| 2686 | TASK_INTERRUPTIBLE); | 2690 | TASK_INTERRUPTIBLE); |
| @@ -2701,8 +2705,8 @@ static int nilfs_segctor_thread(void *arg) | |||
| 2701 | finish_wait(&sci->sc_wait_daemon, &wait); | 2705 | finish_wait(&sci->sc_wait_daemon, &wait); |
| 2702 | timeout = ((sci->sc_state & NILFS_SEGCTOR_COMMIT) && | 2706 | timeout = ((sci->sc_state & NILFS_SEGCTOR_COMMIT) && |
| 2703 | time_after_eq(jiffies, sci->sc_timer->expires)); | 2707 | time_after_eq(jiffies, sci->sc_timer->expires)); |
| 2704 | nilfs = sci->sc_sbi->s_nilfs; | 2708 | |
| 2705 | if (sci->sc_super->s_dirt && nilfs_sb_need_update(nilfs)) | 2709 | if (nilfs_sb_dirty(nilfs) && nilfs_sb_need_update(nilfs)) |
| 2706 | set_nilfs_discontinued(nilfs); | 2710 | set_nilfs_discontinued(nilfs); |
| 2707 | } | 2711 | } |
| 2708 | goto loop; | 2712 | goto loop; |
| @@ -2797,12 +2801,9 @@ static void nilfs_segctor_write_out(struct nilfs_sc_info *sci) | |||
| 2797 | do { | 2801 | do { |
| 2798 | struct nilfs_sb_info *sbi = sci->sc_sbi; | 2802 | struct nilfs_sb_info *sbi = sci->sc_sbi; |
| 2799 | struct nilfs_transaction_info ti; | 2803 | struct nilfs_transaction_info ti; |
| 2800 | struct nilfs_segctor_req req = { .mode = SC_LSEG_SR }; | ||
| 2801 | 2804 | ||
| 2802 | nilfs_transaction_lock(sbi, &ti, 0); | 2805 | nilfs_transaction_lock(sbi, &ti, 0); |
| 2803 | nilfs_segctor_accept(sci, &req); | 2806 | ret = nilfs_segctor_construct(sci, SC_LSEG_SR); |
| 2804 | ret = nilfs_segctor_construct(sci, &req); | ||
| 2805 | nilfs_segctor_notify(sci, &req); | ||
| 2806 | nilfs_transaction_unlock(sbi); | 2807 | nilfs_transaction_unlock(sbi); |
| 2807 | 2808 | ||
| 2808 | } while (ret && retrycount-- > 0); | 2809 | } while (ret && retrycount-- > 0); |
| @@ -2865,8 +2866,15 @@ int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi) | |||
| 2865 | struct the_nilfs *nilfs = sbi->s_nilfs; | 2866 | struct the_nilfs *nilfs = sbi->s_nilfs; |
| 2866 | int err; | 2867 | int err; |
| 2867 | 2868 | ||
| 2868 | /* Each field of nilfs_segctor is cleared through the initialization | 2869 | if (NILFS_SC(sbi)) { |
| 2869 | of super-block info */ | 2870 | /* |
| 2871 | * This happens if the filesystem was remounted | ||
| 2872 | * read/write after nilfs_error degenerated it into a | ||
| 2873 | * read-only mount. | ||
| 2874 | */ | ||
| 2875 | nilfs_detach_segment_constructor(sbi); | ||
| 2876 | } | ||
| 2877 | |||
| 2870 | sbi->s_sc_info = nilfs_segctor_new(sbi); | 2878 | sbi->s_sc_info = nilfs_segctor_new(sbi); |
| 2871 | if (!sbi->s_sc_info) | 2879 | if (!sbi->s_sc_info) |
| 2872 | return -ENOMEM; | 2880 | return -ENOMEM; |
diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index 3d3ab2f9864c..3155e0c7f415 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h | |||
| @@ -116,6 +116,7 @@ struct nilfs_segsum_pointer { | |||
| 116 | * @sc_wait_daemon: Daemon wait queue | 116 | * @sc_wait_daemon: Daemon wait queue |
| 117 | * @sc_wait_task: Start/end wait queue to control segctord task | 117 | * @sc_wait_task: Start/end wait queue to control segctord task |
| 118 | * @sc_seq_request: Request counter | 118 | * @sc_seq_request: Request counter |
| 119 | * @sc_seq_accept: Accepted request count | ||
| 119 | * @sc_seq_done: Completion counter | 120 | * @sc_seq_done: Completion counter |
| 120 | * @sc_sync: Request of explicit sync operation | 121 | * @sc_sync: Request of explicit sync operation |
| 121 | * @sc_interval: Timeout value of background construction | 122 | * @sc_interval: Timeout value of background construction |
| @@ -169,6 +170,7 @@ struct nilfs_sc_info { | |||
| 169 | wait_queue_head_t sc_wait_task; | 170 | wait_queue_head_t sc_wait_task; |
| 170 | 171 | ||
| 171 | __u32 sc_seq_request; | 172 | __u32 sc_seq_request; |
| 173 | __u32 sc_seq_accepted; | ||
| 172 | __u32 sc_seq_done; | 174 | __u32 sc_seq_done; |
| 173 | 175 | ||
| 174 | int sc_sync; | 176 | int sc_sync; |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 8173faee31e6..92579cc4c935 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
| @@ -96,9 +96,6 @@ void nilfs_error(struct super_block *sb, const char *function, | |||
| 96 | if (!(sb->s_flags & MS_RDONLY)) { | 96 | if (!(sb->s_flags & MS_RDONLY)) { |
| 97 | struct the_nilfs *nilfs = sbi->s_nilfs; | 97 | struct the_nilfs *nilfs = sbi->s_nilfs; |
| 98 | 98 | ||
| 99 | if (!nilfs_test_opt(sbi, ERRORS_CONT)) | ||
| 100 | nilfs_detach_segment_constructor(sbi); | ||
| 101 | |||
| 102 | down_write(&nilfs->ns_sem); | 99 | down_write(&nilfs->ns_sem); |
| 103 | if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) { | 100 | if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) { |
| 104 | nilfs->ns_mount_state |= NILFS_ERROR_FS; | 101 | nilfs->ns_mount_state |= NILFS_ERROR_FS; |
| @@ -301,7 +298,7 @@ int nilfs_commit_super(struct nilfs_sb_info *sbi, int dupsb) | |||
| 301 | memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); | 298 | memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); |
| 302 | nilfs->ns_sbwtime[1] = t; | 299 | nilfs->ns_sbwtime[1] = t; |
| 303 | } | 300 | } |
| 304 | sbi->s_super->s_dirt = 0; | 301 | clear_nilfs_sb_dirty(nilfs); |
| 305 | return nilfs_sync_super(sbi, dupsb); | 302 | return nilfs_sync_super(sbi, dupsb); |
| 306 | } | 303 | } |
| 307 | 304 | ||
| @@ -345,7 +342,7 @@ static int nilfs_sync_fs(struct super_block *sb, int wait) | |||
| 345 | err = nilfs_construct_segment(sb); | 342 | err = nilfs_construct_segment(sb); |
| 346 | 343 | ||
| 347 | down_write(&nilfs->ns_sem); | 344 | down_write(&nilfs->ns_sem); |
| 348 | if (sb->s_dirt) | 345 | if (nilfs_sb_dirty(nilfs)) |
| 349 | nilfs_commit_super(sbi, 1); | 346 | nilfs_commit_super(sbi, 1); |
| 350 | up_write(&nilfs->ns_sem); | 347 | up_write(&nilfs->ns_sem); |
| 351 | 348 | ||
| @@ -481,6 +478,8 @@ static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
| 481 | seq_printf(seq, ",order=strict"); | 478 | seq_printf(seq, ",order=strict"); |
| 482 | if (nilfs_test_opt(sbi, NORECOVERY)) | 479 | if (nilfs_test_opt(sbi, NORECOVERY)) |
| 483 | seq_printf(seq, ",norecovery"); | 480 | seq_printf(seq, ",norecovery"); |
| 481 | if (nilfs_test_opt(sbi, DISCARD)) | ||
| 482 | seq_printf(seq, ",discard"); | ||
| 484 | 483 | ||
| 485 | return 0; | 484 | return 0; |
| 486 | } | 485 | } |
| @@ -550,7 +549,7 @@ static const struct export_operations nilfs_export_ops = { | |||
| 550 | enum { | 549 | enum { |
| 551 | Opt_err_cont, Opt_err_panic, Opt_err_ro, | 550 | Opt_err_cont, Opt_err_panic, Opt_err_ro, |
| 552 | Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery, | 551 | Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery, |
| 553 | Opt_err, | 552 | Opt_discard, Opt_err, |
| 554 | }; | 553 | }; |
| 555 | 554 | ||
| 556 | static match_table_t tokens = { | 555 | static match_table_t tokens = { |
| @@ -561,6 +560,7 @@ static match_table_t tokens = { | |||
| 561 | {Opt_snapshot, "cp=%u"}, | 560 | {Opt_snapshot, "cp=%u"}, |
| 562 | {Opt_order, "order=%s"}, | 561 | {Opt_order, "order=%s"}, |
| 563 | {Opt_norecovery, "norecovery"}, | 562 | {Opt_norecovery, "norecovery"}, |
| 563 | {Opt_discard, "discard"}, | ||
| 564 | {Opt_err, NULL} | 564 | {Opt_err, NULL} |
| 565 | }; | 565 | }; |
| 566 | 566 | ||
| @@ -614,6 +614,9 @@ static int parse_options(char *options, struct super_block *sb) | |||
| 614 | case Opt_norecovery: | 614 | case Opt_norecovery: |
| 615 | nilfs_set_opt(sbi, NORECOVERY); | 615 | nilfs_set_opt(sbi, NORECOVERY); |
| 616 | break; | 616 | break; |
| 617 | case Opt_discard: | ||
| 618 | nilfs_set_opt(sbi, DISCARD); | ||
| 619 | break; | ||
| 617 | default: | 620 | default: |
| 618 | printk(KERN_ERR | 621 | printk(KERN_ERR |
| 619 | "NILFS: Unrecognized mount option \"%s\"\n", p); | 622 | "NILFS: Unrecognized mount option \"%s\"\n", p); |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 6241e1722efc..92733d5651d2 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
| @@ -646,6 +646,44 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
| 646 | goto out; | 646 | goto out; |
| 647 | } | 647 | } |
| 648 | 648 | ||
| 649 | int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump, | ||
| 650 | size_t nsegs) | ||
| 651 | { | ||
| 652 | sector_t seg_start, seg_end; | ||
| 653 | sector_t start = 0, nblocks = 0; | ||
| 654 | unsigned int sects_per_block; | ||
| 655 | __u64 *sn; | ||
| 656 | int ret = 0; | ||
| 657 | |||
| 658 | sects_per_block = (1 << nilfs->ns_blocksize_bits) / | ||
| 659 | bdev_logical_block_size(nilfs->ns_bdev); | ||
| 660 | for (sn = segnump; sn < segnump + nsegs; sn++) { | ||
| 661 | nilfs_get_segment_range(nilfs, *sn, &seg_start, &seg_end); | ||
| 662 | |||
| 663 | if (!nblocks) { | ||
| 664 | start = seg_start; | ||
| 665 | nblocks = seg_end - seg_start + 1; | ||
| 666 | } else if (start + nblocks == seg_start) { | ||
| 667 | nblocks += seg_end - seg_start + 1; | ||
| 668 | } else { | ||
| 669 | ret = blkdev_issue_discard(nilfs->ns_bdev, | ||
| 670 | start * sects_per_block, | ||
| 671 | nblocks * sects_per_block, | ||
| 672 | GFP_NOFS, | ||
| 673 | DISCARD_FL_BARRIER); | ||
| 674 | if (ret < 0) | ||
| 675 | return ret; | ||
| 676 | nblocks = 0; | ||
| 677 | } | ||
| 678 | } | ||
| 679 | if (nblocks) | ||
| 680 | ret = blkdev_issue_discard(nilfs->ns_bdev, | ||
| 681 | start * sects_per_block, | ||
| 682 | nblocks * sects_per_block, | ||
| 683 | GFP_NOFS, DISCARD_FL_BARRIER); | ||
| 684 | return ret; | ||
| 685 | } | ||
| 686 | |||
| 649 | int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks) | 687 | int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks) |
| 650 | { | 688 | { |
| 651 | struct inode *dat = nilfs_dat_inode(nilfs); | 689 | struct inode *dat = nilfs_dat_inode(nilfs); |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 589786e33464..e9795f1724d7 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
| @@ -38,6 +38,7 @@ enum { | |||
| 38 | the latest checkpoint was loaded */ | 38 | the latest checkpoint was loaded */ |
| 39 | THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */ | 39 | THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */ |
| 40 | THE_NILFS_GC_RUNNING, /* gc process is running */ | 40 | THE_NILFS_GC_RUNNING, /* gc process is running */ |
| 41 | THE_NILFS_SB_DIRTY, /* super block is dirty */ | ||
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 43 | /** | 44 | /** |
| @@ -197,6 +198,7 @@ THE_NILFS_FNS(INIT, init) | |||
| 197 | THE_NILFS_FNS(LOADED, loaded) | 198 | THE_NILFS_FNS(LOADED, loaded) |
| 198 | THE_NILFS_FNS(DISCONTINUED, discontinued) | 199 | THE_NILFS_FNS(DISCONTINUED, discontinued) |
| 199 | THE_NILFS_FNS(GC_RUNNING, gc_running) | 200 | THE_NILFS_FNS(GC_RUNNING, gc_running) |
| 201 | THE_NILFS_FNS(SB_DIRTY, sb_dirty) | ||
| 200 | 202 | ||
| 201 | /* Minimum interval of periodical update of superblocks (in seconds) */ | 203 | /* Minimum interval of periodical update of superblocks (in seconds) */ |
| 202 | #define NILFS_SB_FREQ 10 | 204 | #define NILFS_SB_FREQ 10 |
| @@ -221,6 +223,7 @@ struct the_nilfs *find_or_create_nilfs(struct block_device *); | |||
| 221 | void put_nilfs(struct the_nilfs *); | 223 | void put_nilfs(struct the_nilfs *); |
| 222 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); | 224 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); |
| 223 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); | 225 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); |
| 226 | int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t); | ||
| 224 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); | 227 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); |
| 225 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64); | 228 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64); |
| 226 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); | 229 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); |
diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h index 3fe02cf8b65a..640702e97457 100644 --- a/include/linux/nilfs2_fs.h +++ b/include/linux/nilfs2_fs.h | |||
| @@ -153,6 +153,7 @@ struct nilfs_super_root { | |||
| 153 | semantics also for data */ | 153 | semantics also for data */ |
| 154 | #define NILFS_MOUNT_NORECOVERY 0x4000 /* Disable write access during | 154 | #define NILFS_MOUNT_NORECOVERY 0x4000 /* Disable write access during |
| 155 | mount-time recovery */ | 155 | mount-time recovery */ |
| 156 | #define NILFS_MOUNT_DISCARD 0x8000 /* Issue DISCARD requests */ | ||
| 156 | 157 | ||
| 157 | 158 | ||
| 158 | /** | 159 | /** |
