mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-06-07 15:15:29 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2: nilfs2: add reader's lock for cno in nilfs_ioctl_sync nilfs2: delete unnecessary condition in load_segment_summary nilfs2: move iterator to write log into segment buffer nilfs2: get rid of s_dirt flag use nilfs2: get rid of nilfs_segctor_req struct nilfs2: delete unnecessary condition in nilfs_dat_translate nilfs2: fix potential hang in nilfs_error on errors=remount-ro nilfs2: use mnt_want_write in ioctls where write access is needed nilfs2: issue discard request after cleaning segments
This commit is contained in:
commit
feaf77d51a
12 changed files with 200 additions and 117 deletions
|
@ -74,6 +74,9 @@ norecovery Disable recovery of the filesystem on mount.
|
||||||
This disables every write access on the device for
|
This disables every write access on the device for
|
||||||
read-only mounts or snapshots. This option will fail
|
read-only mounts or snapshots. This option will fail
|
||||||
for r/w mounts on an unclean volume.
|
for r/w mounts on an unclean volume.
|
||||||
|
discard Issue discard/TRIM commands to the underlying block
|
||||||
|
device when blocks are freed. This is useful for SSD
|
||||||
|
devices and sparse/thinly-provisioned LUNs.
|
||||||
|
|
||||||
NILFS2 usage
|
NILFS2 usage
|
||||||
============
|
============
|
||||||
|
|
|
@ -388,8 +388,7 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (blocknrp != NULL)
|
*blocknrp = blocknr;
|
||||||
*blocknrp = blocknr;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kunmap_atomic(kaddr, KM_USER0);
|
kunmap_atomic(kaddr, KM_USER0);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/capability.h> /* capable() */
|
#include <linux/capability.h> /* capable() */
|
||||||
#include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */
|
#include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/mount.h> /* mnt_want_write(), mnt_drop_write() */
|
||||||
#include <linux/nilfs2_fs.h>
|
#include <linux/nilfs2_fs.h>
|
||||||
#include "nilfs.h"
|
#include "nilfs.h"
|
||||||
#include "segment.h"
|
#include "segment.h"
|
||||||
|
@ -107,20 +108,28 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
ret = mnt_want_write(filp->f_path.mnt);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = -EFAULT;
|
||||||
if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
|
if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
|
||||||
return -EFAULT;
|
goto out;
|
||||||
|
|
||||||
mutex_lock(&nilfs->ns_mount_mutex);
|
mutex_lock(&nilfs->ns_mount_mutex);
|
||||||
|
|
||||||
nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
||||||
ret = nilfs_cpfile_change_cpmode(
|
ret = nilfs_cpfile_change_cpmode(
|
||||||
cpfile, cpmode.cm_cno, cpmode.cm_mode);
|
cpfile, cpmode.cm_cno, cpmode.cm_mode);
|
||||||
if (unlikely(ret < 0)) {
|
if (unlikely(ret < 0))
|
||||||
nilfs_transaction_abort(inode->i_sb);
|
nilfs_transaction_abort(inode->i_sb);
|
||||||
mutex_unlock(&nilfs->ns_mount_mutex);
|
else
|
||||||
return ret;
|
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
||||||
}
|
|
||||||
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
|
||||||
mutex_unlock(&nilfs->ns_mount_mutex);
|
mutex_unlock(&nilfs->ns_mount_mutex);
|
||||||
|
out:
|
||||||
|
mnt_drop_write(filp->f_path.mnt);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,16 +144,23 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
ret = mnt_want_write(filp->f_path.mnt);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = -EFAULT;
|
||||||
if (copy_from_user(&cno, argp, sizeof(cno)))
|
if (copy_from_user(&cno, argp, sizeof(cno)))
|
||||||
return -EFAULT;
|
goto out;
|
||||||
|
|
||||||
nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
||||||
ret = nilfs_cpfile_delete_checkpoint(cpfile, cno);
|
ret = nilfs_cpfile_delete_checkpoint(cpfile, cno);
|
||||||
if (unlikely(ret < 0)) {
|
if (unlikely(ret < 0))
|
||||||
nilfs_transaction_abort(inode->i_sb);
|
nilfs_transaction_abort(inode->i_sb);
|
||||||
return ret;
|
else
|
||||||
}
|
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
||||||
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
out:
|
||||||
|
mnt_drop_write(filp->f_path.mnt);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,12 +512,19 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (copy_from_user(argv, argp, sizeof(argv)))
|
ret = mnt_want_write(filp->f_path.mnt);
|
||||||
return -EFAULT;
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = -EFAULT;
|
||||||
|
if (copy_from_user(argv, argp, sizeof(argv)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = -EINVAL;
|
||||||
nsegs = argv[4].v_nmembs;
|
nsegs = argv[4].v_nmembs;
|
||||||
if (argv[4].v_size != argsz[4])
|
if (argv[4].v_size != argsz[4])
|
||||||
return -EINVAL;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* argv[4] points to segment numbers this ioctl cleans. We
|
* argv[4] points to segment numbers this ioctl cleans. We
|
||||||
* use kmalloc() for its buffer because memory used for the
|
* 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,
|
||||||
*/
|
*/
|
||||||
kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base,
|
kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base,
|
||||||
nsegs * sizeof(__u64));
|
nsegs * sizeof(__u64));
|
||||||
if (IS_ERR(kbufs[4]))
|
if (IS_ERR(kbufs[4])) {
|
||||||
return PTR_ERR(kbufs[4]);
|
ret = PTR_ERR(kbufs[4]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
|
nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
|
||||||
|
|
||||||
for (n = 0; n < 4; n++) {
|
for (n = 0; n < 4; n++) {
|
||||||
|
@ -563,10 +587,12 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
|
||||||
nilfs_remove_all_gcinode(nilfs);
|
nilfs_remove_all_gcinode(nilfs);
|
||||||
clear_nilfs_gc_running(nilfs);
|
clear_nilfs_gc_running(nilfs);
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
while (--n >= 0)
|
while (--n >= 0)
|
||||||
vfree(kbufs[n]);
|
vfree(kbufs[n]);
|
||||||
kfree(kbufs[4]);
|
kfree(kbufs[4]);
|
||||||
|
out:
|
||||||
|
mnt_drop_write(filp->f_path.mnt);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,13 +601,17 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
|
||||||
{
|
{
|
||||||
__u64 cno;
|
__u64 cno;
|
||||||
int ret;
|
int ret;
|
||||||
|
struct the_nilfs *nilfs;
|
||||||
|
|
||||||
ret = nilfs_construct_segment(inode->i_sb);
|
ret = nilfs_construct_segment(inode->i_sb);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (argp != NULL) {
|
if (argp != NULL) {
|
||||||
cno = NILFS_SB(inode->i_sb)->s_nilfs->ns_cno - 1;
|
nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
|
||||||
|
down_read(&nilfs->ns_segctor_sem);
|
||||||
|
cno = nilfs->ns_cno - 1;
|
||||||
|
up_read(&nilfs->ns_segctor_sem);
|
||||||
if (copy_to_user(argp, &cno, sizeof(cno)))
|
if (copy_to_user(argp, &cno, sizeof(cno)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ enum {
|
||||||
NILFS_SEG_FAIL_IO,
|
NILFS_SEG_FAIL_IO,
|
||||||
NILFS_SEG_FAIL_MAGIC,
|
NILFS_SEG_FAIL_MAGIC,
|
||||||
NILFS_SEG_FAIL_SEQ,
|
NILFS_SEG_FAIL_SEQ,
|
||||||
NILFS_SEG_FAIL_CHECKSUM_SEGSUM,
|
|
||||||
NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT,
|
NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT,
|
||||||
NILFS_SEG_FAIL_CHECKSUM_FULL,
|
NILFS_SEG_FAIL_CHECKSUM_FULL,
|
||||||
NILFS_SEG_FAIL_CONSISTENCY,
|
NILFS_SEG_FAIL_CONSISTENCY,
|
||||||
|
@ -71,10 +70,6 @@ static int nilfs_warn_segment_error(int err)
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
"NILFS warning: Sequence number mismatch\n");
|
"NILFS warning: Sequence number mismatch\n");
|
||||||
break;
|
break;
|
||||||
case NILFS_SEG_FAIL_CHECKSUM_SEGSUM:
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"NILFS warning: Checksum error in segment summary\n");
|
|
||||||
break;
|
|
||||||
case NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT:
|
case NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT:
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
"NILFS warning: Checksum error in super root\n");
|
"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,
|
||||||
* @pseg_start: start disk block number of partial segment
|
* @pseg_start: start disk block number of partial segment
|
||||||
* @seg_seq: sequence number requested
|
* @seg_seq: sequence number requested
|
||||||
* @ssi: pointer to nilfs_segsum_info struct to store information
|
* @ssi: pointer to nilfs_segsum_info struct to store information
|
||||||
* @full_check: full check flag
|
|
||||||
* (0: only checks segment summary CRC, 1: data CRC)
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start,
|
load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start,
|
||||||
u64 seg_seq, struct nilfs_segsum_info *ssi,
|
u64 seg_seq, struct nilfs_segsum_info *ssi)
|
||||||
int full_check)
|
|
||||||
{
|
{
|
||||||
struct buffer_head *bh_sum;
|
struct buffer_head *bh_sum;
|
||||||
struct nilfs_segment_summary *sum;
|
struct nilfs_segment_summary *sum;
|
||||||
unsigned long offset, nblock;
|
unsigned long nblock;
|
||||||
u64 check_bytes;
|
u32 crc;
|
||||||
u32 crc, crc_sum;
|
|
||||||
int ret = NILFS_SEG_FAIL_IO;
|
int ret = NILFS_SEG_FAIL_IO;
|
||||||
|
|
||||||
bh_sum = sb_bread(sbi->s_super, pseg_start);
|
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,
|
||||||
ret = NILFS_SEG_FAIL_SEQ;
|
ret = NILFS_SEG_FAIL_SEQ;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
if (full_check) {
|
|
||||||
offset = sizeof(sum->ss_datasum);
|
|
||||||
check_bytes =
|
|
||||||
((u64)ssi->nblocks << sbi->s_super->s_blocksize_bits);
|
|
||||||
nblock = ssi->nblocks;
|
|
||||||
crc_sum = le32_to_cpu(sum->ss_datasum);
|
|
||||||
ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
|
|
||||||
} else { /* only checks segment summary */
|
|
||||||
offset = sizeof(sum->ss_datasum) + sizeof(sum->ss_sumsum);
|
|
||||||
check_bytes = ssi->sumbytes;
|
|
||||||
nblock = ssi->nsumblk;
|
|
||||||
crc_sum = le32_to_cpu(sum->ss_sumsum);
|
|
||||||
ret = NILFS_SEG_FAIL_CHECKSUM_SEGSUM;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
nblock = ssi->nblocks;
|
||||||
if (unlikely(nblock == 0 ||
|
if (unlikely(nblock == 0 ||
|
||||||
nblock > sbi->s_nilfs->ns_blocks_per_segment)) {
|
nblock > sbi->s_nilfs->ns_blocks_per_segment)) {
|
||||||
/* This limits the number of blocks read in the CRC check */
|
/* This limits the number of blocks read in the CRC check */
|
||||||
ret = NILFS_SEG_FAIL_CONSISTENCY;
|
ret = NILFS_SEG_FAIL_CONSISTENCY;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
if (calc_crc_cont(sbi, bh_sum, &crc, offset, check_bytes,
|
if (calc_crc_cont(sbi, bh_sum, &crc, sizeof(sum->ss_datasum),
|
||||||
|
((u64)nblock << sbi->s_super->s_blocksize_bits),
|
||||||
pseg_start, nblock)) {
|
pseg_start, nblock)) {
|
||||||
ret = NILFS_SEG_FAIL_IO;
|
ret = NILFS_SEG_FAIL_IO;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
if (crc == crc_sum)
|
if (crc == le32_to_cpu(sum->ss_datasum))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
else
|
||||||
|
ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
|
||||||
failed:
|
failed:
|
||||||
brelse(bh_sum);
|
brelse(bh_sum);
|
||||||
out:
|
out:
|
||||||
|
@ -598,7 +579,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
|
||||||
|
|
||||||
while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {
|
while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {
|
||||||
|
|
||||||
ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi, 1);
|
ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret == NILFS_SEG_FAIL_IO) {
|
if (ret == NILFS_SEG_FAIL_IO) {
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
|
@ -821,7 +802,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Load segment summary */
|
/* Load segment summary */
|
||||||
ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi, 1);
|
ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret == NILFS_SEG_FAIL_IO)
|
if (ret == NILFS_SEG_FAIL_IO)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
|
@ -40,6 +40,11 @@ struct nilfs_write_info {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,
|
||||||
|
struct the_nilfs *nilfs);
|
||||||
|
static int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf);
|
||||||
|
|
||||||
|
|
||||||
static struct kmem_cache *nilfs_segbuf_cachep;
|
static struct kmem_cache *nilfs_segbuf_cachep;
|
||||||
|
|
||||||
static void nilfs_segbuf_init_once(void *obj)
|
static void nilfs_segbuf_init_once(void *obj)
|
||||||
|
@ -302,6 +307,19 @@ void nilfs_truncate_logs(struct list_head *logs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs)
|
||||||
|
{
|
||||||
|
struct nilfs_segment_buffer *segbuf;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
list_for_each_entry(segbuf, logs, sb_list) {
|
||||||
|
ret = nilfs_segbuf_write(segbuf, nilfs);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int nilfs_wait_on_logs(struct list_head *logs)
|
int nilfs_wait_on_logs(struct list_head *logs)
|
||||||
{
|
{
|
||||||
struct nilfs_segment_buffer *segbuf;
|
struct nilfs_segment_buffer *segbuf;
|
||||||
|
|
|
@ -166,13 +166,10 @@ nilfs_segbuf_add_file_buffer(struct nilfs_segment_buffer *segbuf,
|
||||||
segbuf->sb_sum.nfileblk++;
|
segbuf->sb_sum.nfileblk++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,
|
|
||||||
struct the_nilfs *nilfs);
|
|
||||||
int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf);
|
|
||||||
|
|
||||||
void nilfs_clear_logs(struct list_head *logs);
|
void nilfs_clear_logs(struct list_head *logs);
|
||||||
void nilfs_truncate_logs(struct list_head *logs,
|
void nilfs_truncate_logs(struct list_head *logs,
|
||||||
struct nilfs_segment_buffer *last);
|
struct nilfs_segment_buffer *last);
|
||||||
|
int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs);
|
||||||
int nilfs_wait_on_logs(struct list_head *logs);
|
int nilfs_wait_on_logs(struct list_head *logs);
|
||||||
|
|
||||||
static inline void nilfs_destroy_logs(struct list_head *logs)
|
static inline void nilfs_destroy_logs(struct list_head *logs)
|
||||||
|
|
|
@ -1764,14 +1764,9 @@ static int nilfs_segctor_prepare_write(struct nilfs_sc_info *sci,
|
||||||
static int nilfs_segctor_write(struct nilfs_sc_info *sci,
|
static int nilfs_segctor_write(struct nilfs_sc_info *sci,
|
||||||
struct the_nilfs *nilfs)
|
struct the_nilfs *nilfs)
|
||||||
{
|
{
|
||||||
struct nilfs_segment_buffer *segbuf;
|
int ret;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) {
|
ret = nilfs_write_logs(&sci->sc_segbufs, nilfs);
|
||||||
ret = nilfs_segbuf_write(segbuf, nilfs);
|
|
||||||
if (ret)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
list_splice_tail_init(&sci->sc_segbufs, &sci->sc_write_logs);
|
list_splice_tail_init(&sci->sc_segbufs, &sci->sc_write_logs);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1937,8 +1932,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
|
||||||
{
|
{
|
||||||
struct nilfs_segment_buffer *segbuf;
|
struct nilfs_segment_buffer *segbuf;
|
||||||
struct page *bd_page = NULL, *fs_page = NULL;
|
struct page *bd_page = NULL, *fs_page = NULL;
|
||||||
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
|
||||||
struct the_nilfs *nilfs = sbi->s_nilfs;
|
|
||||||
int update_sr = (sci->sc_super_root != NULL);
|
int update_sr = (sci->sc_super_root != NULL);
|
||||||
|
|
||||||
list_for_each_entry(segbuf, &sci->sc_write_logs, sb_list) {
|
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)
|
||||||
if (update_sr) {
|
if (update_sr) {
|
||||||
nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
|
nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
|
||||||
segbuf->sb_sum.seg_seq, nilfs->ns_cno++);
|
segbuf->sb_sum.seg_seq, nilfs->ns_cno++);
|
||||||
sbi->s_super->s_dirt = 1;
|
set_nilfs_sb_dirty(nilfs);
|
||||||
|
|
||||||
clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags);
|
clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags);
|
||||||
clear_bit(NILFS_SC_DIRTY, &sci->sc_flags);
|
clear_bit(NILFS_SC_DIRTY, &sci->sc_flags);
|
||||||
|
@ -2425,43 +2419,43 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nilfs_segctor_req {
|
|
||||||
int mode;
|
|
||||||
__u32 seq_accepted;
|
|
||||||
int sc_err; /* construction failure */
|
|
||||||
int sb_err; /* super block writeback failure */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FLUSH_FILE_BIT (0x1) /* data file only */
|
#define FLUSH_FILE_BIT (0x1) /* data file only */
|
||||||
#define FLUSH_DAT_BIT (1 << NILFS_DAT_INO) /* DAT only */
|
#define FLUSH_DAT_BIT (1 << NILFS_DAT_INO) /* DAT only */
|
||||||
|
|
||||||
static void nilfs_segctor_accept(struct nilfs_sc_info *sci,
|
/**
|
||||||
struct nilfs_segctor_req *req)
|
* nilfs_segctor_accept - record accepted sequence count of log-write requests
|
||||||
|
* @sci: segment constructor object
|
||||||
|
*/
|
||||||
|
static void nilfs_segctor_accept(struct nilfs_sc_info *sci)
|
||||||
{
|
{
|
||||||
req->sc_err = req->sb_err = 0;
|
|
||||||
spin_lock(&sci->sc_state_lock);
|
spin_lock(&sci->sc_state_lock);
|
||||||
req->seq_accepted = sci->sc_seq_request;
|
sci->sc_seq_accepted = sci->sc_seq_request;
|
||||||
spin_unlock(&sci->sc_state_lock);
|
spin_unlock(&sci->sc_state_lock);
|
||||||
|
|
||||||
if (sci->sc_timer)
|
if (sci->sc_timer)
|
||||||
del_timer_sync(sci->sc_timer);
|
del_timer_sync(sci->sc_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nilfs_segctor_notify(struct nilfs_sc_info *sci,
|
/**
|
||||||
struct nilfs_segctor_req *req)
|
* nilfs_segctor_notify - notify the result of request to caller threads
|
||||||
|
* @sci: segment constructor object
|
||||||
|
* @mode: mode of log forming
|
||||||
|
* @err: error code to be notified
|
||||||
|
*/
|
||||||
|
static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err)
|
||||||
{
|
{
|
||||||
/* Clear requests (even when the construction failed) */
|
/* Clear requests (even when the construction failed) */
|
||||||
spin_lock(&sci->sc_state_lock);
|
spin_lock(&sci->sc_state_lock);
|
||||||
|
|
||||||
if (req->mode == SC_LSEG_SR) {
|
if (mode == SC_LSEG_SR) {
|
||||||
sci->sc_state &= ~NILFS_SEGCTOR_COMMIT;
|
sci->sc_state &= ~NILFS_SEGCTOR_COMMIT;
|
||||||
sci->sc_seq_done = req->seq_accepted;
|
sci->sc_seq_done = sci->sc_seq_accepted;
|
||||||
nilfs_segctor_wakeup(sci, req->sc_err ? : req->sb_err);
|
nilfs_segctor_wakeup(sci, err);
|
||||||
sci->sc_flush_request = 0;
|
sci->sc_flush_request = 0;
|
||||||
} else {
|
} else {
|
||||||
if (req->mode == SC_FLUSH_FILE)
|
if (mode == SC_FLUSH_FILE)
|
||||||
sci->sc_flush_request &= ~FLUSH_FILE_BIT;
|
sci->sc_flush_request &= ~FLUSH_FILE_BIT;
|
||||||
else if (req->mode == SC_FLUSH_DAT)
|
else if (mode == SC_FLUSH_DAT)
|
||||||
sci->sc_flush_request &= ~FLUSH_DAT_BIT;
|
sci->sc_flush_request &= ~FLUSH_DAT_BIT;
|
||||||
|
|
||||||
/* re-enable timer if checkpoint creation was not done */
|
/* re-enable timer if checkpoint creation was not done */
|
||||||
|
@ -2472,30 +2466,37 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci,
|
||||||
spin_unlock(&sci->sc_state_lock);
|
spin_unlock(&sci->sc_state_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nilfs_segctor_construct(struct nilfs_sc_info *sci,
|
/**
|
||||||
struct nilfs_segctor_req *req)
|
* nilfs_segctor_construct - form logs and write them to disk
|
||||||
|
* @sci: segment constructor object
|
||||||
|
* @mode: mode of log forming
|
||||||
|
*/
|
||||||
|
static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
|
||||||
{
|
{
|
||||||
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
||||||
struct the_nilfs *nilfs = sbi->s_nilfs;
|
struct the_nilfs *nilfs = sbi->s_nilfs;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
nilfs_segctor_accept(sci);
|
||||||
|
|
||||||
if (nilfs_discontinued(nilfs))
|
if (nilfs_discontinued(nilfs))
|
||||||
req->mode = SC_LSEG_SR;
|
mode = SC_LSEG_SR;
|
||||||
if (!nilfs_segctor_confirm(sci)) {
|
if (!nilfs_segctor_confirm(sci))
|
||||||
err = nilfs_segctor_do_construct(sci, req->mode);
|
err = nilfs_segctor_do_construct(sci, mode);
|
||||||
req->sc_err = err;
|
|
||||||
}
|
|
||||||
if (likely(!err)) {
|
if (likely(!err)) {
|
||||||
if (req->mode != SC_FLUSH_DAT)
|
if (mode != SC_FLUSH_DAT)
|
||||||
atomic_set(&nilfs->ns_ndirtyblks, 0);
|
atomic_set(&nilfs->ns_ndirtyblks, 0);
|
||||||
if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) &&
|
if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) &&
|
||||||
nilfs_discontinued(nilfs)) {
|
nilfs_discontinued(nilfs)) {
|
||||||
down_write(&nilfs->ns_sem);
|
down_write(&nilfs->ns_sem);
|
||||||
req->sb_err = nilfs_commit_super(sbi,
|
err = nilfs_commit_super(
|
||||||
nilfs_altsb_need_update(nilfs));
|
sbi, nilfs_altsb_need_update(nilfs));
|
||||||
up_write(&nilfs->ns_sem);
|
up_write(&nilfs->ns_sem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nilfs_segctor_notify(sci, mode, err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2526,7 +2527,6 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
|
||||||
struct nilfs_sc_info *sci = NILFS_SC(sbi);
|
struct nilfs_sc_info *sci = NILFS_SC(sbi);
|
||||||
struct the_nilfs *nilfs = sbi->s_nilfs;
|
struct the_nilfs *nilfs = sbi->s_nilfs;
|
||||||
struct nilfs_transaction_info ti;
|
struct nilfs_transaction_info ti;
|
||||||
struct nilfs_segctor_req req = { .mode = SC_LSEG_SR };
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (unlikely(!sci))
|
if (unlikely(!sci))
|
||||||
|
@ -2547,10 +2547,8 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
|
||||||
list_splice_tail_init(&nilfs->ns_gc_inodes, &sci->sc_gc_inodes);
|
list_splice_tail_init(&nilfs->ns_gc_inodes, &sci->sc_gc_inodes);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
nilfs_segctor_accept(sci, &req);
|
err = nilfs_segctor_construct(sci, SC_LSEG_SR);
|
||||||
err = nilfs_segctor_construct(sci, &req);
|
|
||||||
nilfs_remove_written_gcinodes(nilfs, &sci->sc_gc_inodes);
|
nilfs_remove_written_gcinodes(nilfs, &sci->sc_gc_inodes);
|
||||||
nilfs_segctor_notify(sci, &req);
|
|
||||||
|
|
||||||
if (likely(!err))
|
if (likely(!err))
|
||||||
break;
|
break;
|
||||||
|
@ -2560,6 +2558,16 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
schedule_timeout(sci->sc_interval);
|
schedule_timeout(sci->sc_interval);
|
||||||
}
|
}
|
||||||
|
if (nilfs_test_opt(sbi, DISCARD)) {
|
||||||
|
int ret = nilfs_discard_segments(nilfs, sci->sc_freesegs,
|
||||||
|
sci->sc_nfreesegs);
|
||||||
|
if (ret) {
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"NILFS warning: error %d on discard request, "
|
||||||
|
"turning discards off for the device\n", ret);
|
||||||
|
nilfs_clear_opt(sbi, DISCARD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
sci->sc_freesegs = NULL;
|
sci->sc_freesegs = NULL;
|
||||||
|
@ -2573,13 +2581,9 @@ static void nilfs_segctor_thread_construct(struct nilfs_sc_info *sci, int mode)
|
||||||
{
|
{
|
||||||
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
||||||
struct nilfs_transaction_info ti;
|
struct nilfs_transaction_info ti;
|
||||||
struct nilfs_segctor_req req = { .mode = mode };
|
|
||||||
|
|
||||||
nilfs_transaction_lock(sbi, &ti, 0);
|
nilfs_transaction_lock(sbi, &ti, 0);
|
||||||
|
nilfs_segctor_construct(sci, mode);
|
||||||
nilfs_segctor_accept(sci, &req);
|
|
||||||
nilfs_segctor_construct(sci, &req);
|
|
||||||
nilfs_segctor_notify(sci, &req);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unclosed segment should be retried. We do this using sc_timer.
|
* 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)
|
||||||
static int nilfs_segctor_thread(void *arg)
|
static int nilfs_segctor_thread(void *arg)
|
||||||
{
|
{
|
||||||
struct nilfs_sc_info *sci = (struct nilfs_sc_info *)arg;
|
struct nilfs_sc_info *sci = (struct nilfs_sc_info *)arg;
|
||||||
|
struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
int timeout = 0;
|
int timeout = 0;
|
||||||
|
|
||||||
|
@ -2680,7 +2685,6 @@ static int nilfs_segctor_thread(void *arg)
|
||||||
} else {
|
} else {
|
||||||
DEFINE_WAIT(wait);
|
DEFINE_WAIT(wait);
|
||||||
int should_sleep = 1;
|
int should_sleep = 1;
|
||||||
struct the_nilfs *nilfs;
|
|
||||||
|
|
||||||
prepare_to_wait(&sci->sc_wait_daemon, &wait,
|
prepare_to_wait(&sci->sc_wait_daemon, &wait,
|
||||||
TASK_INTERRUPTIBLE);
|
TASK_INTERRUPTIBLE);
|
||||||
|
@ -2701,8 +2705,8 @@ static int nilfs_segctor_thread(void *arg)
|
||||||
finish_wait(&sci->sc_wait_daemon, &wait);
|
finish_wait(&sci->sc_wait_daemon, &wait);
|
||||||
timeout = ((sci->sc_state & NILFS_SEGCTOR_COMMIT) &&
|
timeout = ((sci->sc_state & NILFS_SEGCTOR_COMMIT) &&
|
||||||
time_after_eq(jiffies, sci->sc_timer->expires));
|
time_after_eq(jiffies, sci->sc_timer->expires));
|
||||||
nilfs = sci->sc_sbi->s_nilfs;
|
|
||||||
if (sci->sc_super->s_dirt && nilfs_sb_need_update(nilfs))
|
if (nilfs_sb_dirty(nilfs) && nilfs_sb_need_update(nilfs))
|
||||||
set_nilfs_discontinued(nilfs);
|
set_nilfs_discontinued(nilfs);
|
||||||
}
|
}
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -2797,12 +2801,9 @@ static void nilfs_segctor_write_out(struct nilfs_sc_info *sci)
|
||||||
do {
|
do {
|
||||||
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
||||||
struct nilfs_transaction_info ti;
|
struct nilfs_transaction_info ti;
|
||||||
struct nilfs_segctor_req req = { .mode = SC_LSEG_SR };
|
|
||||||
|
|
||||||
nilfs_transaction_lock(sbi, &ti, 0);
|
nilfs_transaction_lock(sbi, &ti, 0);
|
||||||
nilfs_segctor_accept(sci, &req);
|
ret = nilfs_segctor_construct(sci, SC_LSEG_SR);
|
||||||
ret = nilfs_segctor_construct(sci, &req);
|
|
||||||
nilfs_segctor_notify(sci, &req);
|
|
||||||
nilfs_transaction_unlock(sbi);
|
nilfs_transaction_unlock(sbi);
|
||||||
|
|
||||||
} while (ret && retrycount-- > 0);
|
} while (ret && retrycount-- > 0);
|
||||||
|
@ -2865,8 +2866,15 @@ int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi)
|
||||||
struct the_nilfs *nilfs = sbi->s_nilfs;
|
struct the_nilfs *nilfs = sbi->s_nilfs;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Each field of nilfs_segctor is cleared through the initialization
|
if (NILFS_SC(sbi)) {
|
||||||
of super-block info */
|
/*
|
||||||
|
* This happens if the filesystem was remounted
|
||||||
|
* read/write after nilfs_error degenerated it into a
|
||||||
|
* read-only mount.
|
||||||
|
*/
|
||||||
|
nilfs_detach_segment_constructor(sbi);
|
||||||
|
}
|
||||||
|
|
||||||
sbi->s_sc_info = nilfs_segctor_new(sbi);
|
sbi->s_sc_info = nilfs_segctor_new(sbi);
|
||||||
if (!sbi->s_sc_info)
|
if (!sbi->s_sc_info)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -116,6 +116,7 @@ struct nilfs_segsum_pointer {
|
||||||
* @sc_wait_daemon: Daemon wait queue
|
* @sc_wait_daemon: Daemon wait queue
|
||||||
* @sc_wait_task: Start/end wait queue to control segctord task
|
* @sc_wait_task: Start/end wait queue to control segctord task
|
||||||
* @sc_seq_request: Request counter
|
* @sc_seq_request: Request counter
|
||||||
|
* @sc_seq_accept: Accepted request count
|
||||||
* @sc_seq_done: Completion counter
|
* @sc_seq_done: Completion counter
|
||||||
* @sc_sync: Request of explicit sync operation
|
* @sc_sync: Request of explicit sync operation
|
||||||
* @sc_interval: Timeout value of background construction
|
* @sc_interval: Timeout value of background construction
|
||||||
|
@ -169,6 +170,7 @@ struct nilfs_sc_info {
|
||||||
wait_queue_head_t sc_wait_task;
|
wait_queue_head_t sc_wait_task;
|
||||||
|
|
||||||
__u32 sc_seq_request;
|
__u32 sc_seq_request;
|
||||||
|
__u32 sc_seq_accepted;
|
||||||
__u32 sc_seq_done;
|
__u32 sc_seq_done;
|
||||||
|
|
||||||
int sc_sync;
|
int sc_sync;
|
||||||
|
|
|
@ -96,9 +96,6 @@ void nilfs_error(struct super_block *sb, const char *function,
|
||||||
if (!(sb->s_flags & MS_RDONLY)) {
|
if (!(sb->s_flags & MS_RDONLY)) {
|
||||||
struct the_nilfs *nilfs = sbi->s_nilfs;
|
struct the_nilfs *nilfs = sbi->s_nilfs;
|
||||||
|
|
||||||
if (!nilfs_test_opt(sbi, ERRORS_CONT))
|
|
||||||
nilfs_detach_segment_constructor(sbi);
|
|
||||||
|
|
||||||
down_write(&nilfs->ns_sem);
|
down_write(&nilfs->ns_sem);
|
||||||
if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) {
|
if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) {
|
||||||
nilfs->ns_mount_state |= NILFS_ERROR_FS;
|
nilfs->ns_mount_state |= NILFS_ERROR_FS;
|
||||||
|
@ -301,7 +298,7 @@ int nilfs_commit_super(struct nilfs_sb_info *sbi, int dupsb)
|
||||||
memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
|
memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
|
||||||
nilfs->ns_sbwtime[1] = t;
|
nilfs->ns_sbwtime[1] = t;
|
||||||
}
|
}
|
||||||
sbi->s_super->s_dirt = 0;
|
clear_nilfs_sb_dirty(nilfs);
|
||||||
return nilfs_sync_super(sbi, dupsb);
|
return nilfs_sync_super(sbi, dupsb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +342,7 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
|
||||||
err = nilfs_construct_segment(sb);
|
err = nilfs_construct_segment(sb);
|
||||||
|
|
||||||
down_write(&nilfs->ns_sem);
|
down_write(&nilfs->ns_sem);
|
||||||
if (sb->s_dirt)
|
if (nilfs_sb_dirty(nilfs))
|
||||||
nilfs_commit_super(sbi, 1);
|
nilfs_commit_super(sbi, 1);
|
||||||
up_write(&nilfs->ns_sem);
|
up_write(&nilfs->ns_sem);
|
||||||
|
|
||||||
|
@ -481,6 +478,8 @@ static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
||||||
seq_printf(seq, ",order=strict");
|
seq_printf(seq, ",order=strict");
|
||||||
if (nilfs_test_opt(sbi, NORECOVERY))
|
if (nilfs_test_opt(sbi, NORECOVERY))
|
||||||
seq_printf(seq, ",norecovery");
|
seq_printf(seq, ",norecovery");
|
||||||
|
if (nilfs_test_opt(sbi, DISCARD))
|
||||||
|
seq_printf(seq, ",discard");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -550,7 +549,7 @@ static const struct export_operations nilfs_export_ops = {
|
||||||
enum {
|
enum {
|
||||||
Opt_err_cont, Opt_err_panic, Opt_err_ro,
|
Opt_err_cont, Opt_err_panic, Opt_err_ro,
|
||||||
Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
|
Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
|
||||||
Opt_err,
|
Opt_discard, Opt_err,
|
||||||
};
|
};
|
||||||
|
|
||||||
static match_table_t tokens = {
|
static match_table_t tokens = {
|
||||||
|
@ -561,6 +560,7 @@ static match_table_t tokens = {
|
||||||
{Opt_snapshot, "cp=%u"},
|
{Opt_snapshot, "cp=%u"},
|
||||||
{Opt_order, "order=%s"},
|
{Opt_order, "order=%s"},
|
||||||
{Opt_norecovery, "norecovery"},
|
{Opt_norecovery, "norecovery"},
|
||||||
|
{Opt_discard, "discard"},
|
||||||
{Opt_err, NULL}
|
{Opt_err, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -614,6 +614,9 @@ static int parse_options(char *options, struct super_block *sb)
|
||||||
case Opt_norecovery:
|
case Opt_norecovery:
|
||||||
nilfs_set_opt(sbi, NORECOVERY);
|
nilfs_set_opt(sbi, NORECOVERY);
|
||||||
break;
|
break;
|
||||||
|
case Opt_discard:
|
||||||
|
nilfs_set_opt(sbi, DISCARD);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"NILFS: Unrecognized mount option \"%s\"\n", p);
|
"NILFS: Unrecognized mount option \"%s\"\n", p);
|
||||||
|
|
|
@ -646,6 +646,44 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump,
|
||||||
|
size_t nsegs)
|
||||||
|
{
|
||||||
|
sector_t seg_start, seg_end;
|
||||||
|
sector_t start = 0, nblocks = 0;
|
||||||
|
unsigned int sects_per_block;
|
||||||
|
__u64 *sn;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
sects_per_block = (1 << nilfs->ns_blocksize_bits) /
|
||||||
|
bdev_logical_block_size(nilfs->ns_bdev);
|
||||||
|
for (sn = segnump; sn < segnump + nsegs; sn++) {
|
||||||
|
nilfs_get_segment_range(nilfs, *sn, &seg_start, &seg_end);
|
||||||
|
|
||||||
|
if (!nblocks) {
|
||||||
|
start = seg_start;
|
||||||
|
nblocks = seg_end - seg_start + 1;
|
||||||
|
} else if (start + nblocks == seg_start) {
|
||||||
|
nblocks += seg_end - seg_start + 1;
|
||||||
|
} else {
|
||||||
|
ret = blkdev_issue_discard(nilfs->ns_bdev,
|
||||||
|
start * sects_per_block,
|
||||||
|
nblocks * sects_per_block,
|
||||||
|
GFP_NOFS,
|
||||||
|
DISCARD_FL_BARRIER);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
nblocks = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nblocks)
|
||||||
|
ret = blkdev_issue_discard(nilfs->ns_bdev,
|
||||||
|
start * sects_per_block,
|
||||||
|
nblocks * sects_per_block,
|
||||||
|
GFP_NOFS, DISCARD_FL_BARRIER);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks)
|
int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks)
|
||||||
{
|
{
|
||||||
struct inode *dat = nilfs_dat_inode(nilfs);
|
struct inode *dat = nilfs_dat_inode(nilfs);
|
||||||
|
|
|
@ -38,6 +38,7 @@ enum {
|
||||||
the latest checkpoint was loaded */
|
the latest checkpoint was loaded */
|
||||||
THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */
|
THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */
|
||||||
THE_NILFS_GC_RUNNING, /* gc process is running */
|
THE_NILFS_GC_RUNNING, /* gc process is running */
|
||||||
|
THE_NILFS_SB_DIRTY, /* super block is dirty */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,6 +198,7 @@ THE_NILFS_FNS(INIT, init)
|
||||||
THE_NILFS_FNS(LOADED, loaded)
|
THE_NILFS_FNS(LOADED, loaded)
|
||||||
THE_NILFS_FNS(DISCONTINUED, discontinued)
|
THE_NILFS_FNS(DISCONTINUED, discontinued)
|
||||||
THE_NILFS_FNS(GC_RUNNING, gc_running)
|
THE_NILFS_FNS(GC_RUNNING, gc_running)
|
||||||
|
THE_NILFS_FNS(SB_DIRTY, sb_dirty)
|
||||||
|
|
||||||
/* Minimum interval of periodical update of superblocks (in seconds) */
|
/* Minimum interval of periodical update of superblocks (in seconds) */
|
||||||
#define NILFS_SB_FREQ 10
|
#define NILFS_SB_FREQ 10
|
||||||
|
@ -221,6 +223,7 @@ struct the_nilfs *find_or_create_nilfs(struct block_device *);
|
||||||
void put_nilfs(struct the_nilfs *);
|
void put_nilfs(struct the_nilfs *);
|
||||||
int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
|
int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
|
||||||
int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);
|
int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);
|
||||||
|
int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t);
|
||||||
int nilfs_count_free_blocks(struct the_nilfs *, sector_t *);
|
int nilfs_count_free_blocks(struct the_nilfs *, sector_t *);
|
||||||
struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
|
struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
|
||||||
int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int);
|
int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int);
|
||||||
|
|
|
@ -153,6 +153,7 @@ struct nilfs_super_root {
|
||||||
semantics also for data */
|
semantics also for data */
|
||||||
#define NILFS_MOUNT_NORECOVERY 0x4000 /* Disable write access during
|
#define NILFS_MOUNT_NORECOVERY 0x4000 /* Disable write access during
|
||||||
mount-time recovery */
|
mount-time recovery */
|
||||||
|
#define NILFS_MOUNT_DISCARD 0x8000 /* Issue DISCARD requests */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue