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:
Коммит
feaf77d51a
|
@ -74,6 +74,9 @@ norecovery Disable recovery of the filesystem on mount.
|
|||
This disables every write access on the device for
|
||||
read-only mounts or snapshots. This option will fail
|
||||
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
|
||||
============
|
||||
|
|
|
@ -388,8 +388,7 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)
|
|||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
if (blocknrp != NULL)
|
||||
*blocknrp = blocknr;
|
||||
*blocknrp = blocknr;
|
||||
|
||||
out:
|
||||
kunmap_atomic(kaddr, KM_USER0);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/capability.h> /* capable() */
|
||||
#include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mount.h> /* mnt_want_write(), mnt_drop_write() */
|
||||
#include <linux/nilfs2_fs.h>
|
||||
#include "nilfs.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))
|
||||
return -EPERM;
|
||||
|
||||
ret = mnt_want_write(filp->f_path.mnt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = -EFAULT;
|
||||
if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
|
||||
return -EFAULT;
|
||||
goto out;
|
||||
|
||||
mutex_lock(&nilfs->ns_mount_mutex);
|
||||
|
||||
nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
||||
ret = nilfs_cpfile_change_cpmode(
|
||||
cpfile, cpmode.cm_cno, cpmode.cm_mode);
|
||||
if (unlikely(ret < 0)) {
|
||||
if (unlikely(ret < 0))
|
||||
nilfs_transaction_abort(inode->i_sb);
|
||||
mutex_unlock(&nilfs->ns_mount_mutex);
|
||||
return ret;
|
||||
}
|
||||
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
||||
else
|
||||
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
||||
|
||||
mutex_unlock(&nilfs->ns_mount_mutex);
|
||||
out:
|
||||
mnt_drop_write(filp->f_path.mnt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -135,16 +144,23 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
|
|||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
ret = mnt_want_write(filp->f_path.mnt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = -EFAULT;
|
||||
if (copy_from_user(&cno, argp, sizeof(cno)))
|
||||
return -EFAULT;
|
||||
goto out;
|
||||
|
||||
nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
||||
ret = nilfs_cpfile_delete_checkpoint(cpfile, cno);
|
||||
if (unlikely(ret < 0)) {
|
||||
if (unlikely(ret < 0))
|
||||
nilfs_transaction_abort(inode->i_sb);
|
||||
return ret;
|
||||
}
|
||||
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
||||
else
|
||||
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
||||
out:
|
||||
mnt_drop_write(filp->f_path.mnt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -496,12 +512,19 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
|
|||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(argv, argp, sizeof(argv)))
|
||||
return -EFAULT;
|
||||
ret = mnt_want_write(filp->f_path.mnt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = -EFAULT;
|
||||
if (copy_from_user(argv, argp, sizeof(argv)))
|
||||
goto out;
|
||||
|
||||
ret = -EINVAL;
|
||||
nsegs = argv[4].v_nmembs;
|
||||
if (argv[4].v_size != argsz[4])
|
||||
return -EINVAL;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* argv[4] points to segment numbers this ioctl cleans. We
|
||||
* 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,
|
||||
nsegs * sizeof(__u64));
|
||||
if (IS_ERR(kbufs[4]))
|
||||
return PTR_ERR(kbufs[4]);
|
||||
|
||||
if (IS_ERR(kbufs[4])) {
|
||||
ret = PTR_ERR(kbufs[4]);
|
||||
goto out;
|
||||
}
|
||||
nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
|
||||
|
||||
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);
|
||||
clear_nilfs_gc_running(nilfs);
|
||||
|
||||
out_free:
|
||||
out_free:
|
||||
while (--n >= 0)
|
||||
vfree(kbufs[n]);
|
||||
kfree(kbufs[4]);
|
||||
out:
|
||||
mnt_drop_write(filp->f_path.mnt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -575,13 +601,17 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
|
|||
{
|
||||
__u64 cno;
|
||||
int ret;
|
||||
struct the_nilfs *nilfs;
|
||||
|
||||
ret = nilfs_construct_segment(inode->i_sb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ enum {
|
|||
NILFS_SEG_FAIL_IO,
|
||||
NILFS_SEG_FAIL_MAGIC,
|
||||
NILFS_SEG_FAIL_SEQ,
|
||||
NILFS_SEG_FAIL_CHECKSUM_SEGSUM,
|
||||
NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT,
|
||||
NILFS_SEG_FAIL_CHECKSUM_FULL,
|
||||
NILFS_SEG_FAIL_CONSISTENCY,
|
||||
|
@ -71,10 +70,6 @@ static int nilfs_warn_segment_error(int err)
|
|||
printk(KERN_WARNING
|
||||
"NILFS warning: Sequence number mismatch\n");
|
||||
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:
|
||||
printk(KERN_WARNING
|
||||
"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
|
||||
* @seg_seq: sequence number requested
|
||||
* @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
|
||||
load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start,
|
||||
u64 seg_seq, struct nilfs_segsum_info *ssi,
|
||||
int full_check)
|
||||
u64 seg_seq, struct nilfs_segsum_info *ssi)
|
||||
{
|
||||
struct buffer_head *bh_sum;
|
||||
struct nilfs_segment_summary *sum;
|
||||
unsigned long offset, nblock;
|
||||
u64 check_bytes;
|
||||
u32 crc, crc_sum;
|
||||
unsigned long nblock;
|
||||
u32 crc;
|
||||
int ret = NILFS_SEG_FAIL_IO;
|
||||
|
||||
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;
|
||||
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 ||
|
||||
nblock > sbi->s_nilfs->ns_blocks_per_segment)) {
|
||||
/* This limits the number of blocks read in the CRC check */
|
||||
ret = NILFS_SEG_FAIL_CONSISTENCY;
|
||||
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)) {
|
||||
ret = NILFS_SEG_FAIL_IO;
|
||||
goto failed;
|
||||
}
|
||||
if (crc == crc_sum)
|
||||
if (crc == le32_to_cpu(sum->ss_datasum))
|
||||
ret = 0;
|
||||
else
|
||||
ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
|
||||
failed:
|
||||
brelse(bh_sum);
|
||||
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) {
|
||||
|
||||
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 == NILFS_SEG_FAIL_IO) {
|
||||
err = -EIO;
|
||||
|
@ -821,7 +802,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
|
|||
|
||||
for (;;) {
|
||||
/* 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 == NILFS_SEG_FAIL_IO)
|
||||
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 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)
|
||||
{
|
||||
struct nilfs_segment_buffer *segbuf;
|
||||
|
|
|
@ -166,13 +166,10 @@ nilfs_segbuf_add_file_buffer(struct nilfs_segment_buffer *segbuf,
|
|||
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_truncate_logs(struct list_head *logs,
|
||||
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);
|
||||
|
||||
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,
|
||||
struct the_nilfs *nilfs)
|
||||
{
|
||||
struct nilfs_segment_buffer *segbuf;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) {
|
||||
ret = nilfs_segbuf_write(segbuf, nilfs);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
ret = nilfs_write_logs(&sci->sc_segbufs, nilfs);
|
||||
list_splice_tail_init(&sci->sc_segbufs, &sci->sc_write_logs);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1937,8 +1932,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
|
|||
{
|
||||
struct nilfs_segment_buffer *segbuf;
|
||||
struct page *bd_page = NULL, *fs_page = NULL;
|
||||
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
||||
struct the_nilfs *nilfs = sbi->s_nilfs;
|
||||
struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
|
||||
int update_sr = (sci->sc_super_root != NULL);
|
||||
|
||||
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) {
|
||||
nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
|
||||
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_DIRTY, &sci->sc_flags);
|
||||
|
@ -2425,43 +2419,43 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
|
|||
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_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);
|
||||
req->seq_accepted = sci->sc_seq_request;
|
||||
sci->sc_seq_accepted = sci->sc_seq_request;
|
||||
spin_unlock(&sci->sc_state_lock);
|
||||
|
||||
if (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) */
|
||||
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_seq_done = req->seq_accepted;
|
||||
nilfs_segctor_wakeup(sci, req->sc_err ? : req->sb_err);
|
||||
sci->sc_seq_done = sci->sc_seq_accepted;
|
||||
nilfs_segctor_wakeup(sci, err);
|
||||
sci->sc_flush_request = 0;
|
||||
} else {
|
||||
if (req->mode == SC_FLUSH_FILE)
|
||||
if (mode == SC_FLUSH_FILE)
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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 the_nilfs *nilfs = sbi->s_nilfs;
|
||||
int err = 0;
|
||||
|
||||
nilfs_segctor_accept(sci);
|
||||
|
||||
if (nilfs_discontinued(nilfs))
|
||||
req->mode = SC_LSEG_SR;
|
||||
if (!nilfs_segctor_confirm(sci)) {
|
||||
err = nilfs_segctor_do_construct(sci, req->mode);
|
||||
req->sc_err = err;
|
||||
}
|
||||
mode = SC_LSEG_SR;
|
||||
if (!nilfs_segctor_confirm(sci))
|
||||
err = nilfs_segctor_do_construct(sci, mode);
|
||||
|
||||
if (likely(!err)) {
|
||||
if (req->mode != SC_FLUSH_DAT)
|
||||
if (mode != SC_FLUSH_DAT)
|
||||
atomic_set(&nilfs->ns_ndirtyblks, 0);
|
||||
if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) &&
|
||||
nilfs_discontinued(nilfs)) {
|
||||
down_write(&nilfs->ns_sem);
|
||||
req->sb_err = nilfs_commit_super(sbi,
|
||||
nilfs_altsb_need_update(nilfs));
|
||||
err = nilfs_commit_super(
|
||||
sbi, nilfs_altsb_need_update(nilfs));
|
||||
up_write(&nilfs->ns_sem);
|
||||
}
|
||||
}
|
||||
|
||||
nilfs_segctor_notify(sci, mode, 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 the_nilfs *nilfs = sbi->s_nilfs;
|
||||
struct nilfs_transaction_info ti;
|
||||
struct nilfs_segctor_req req = { .mode = SC_LSEG_SR };
|
||||
int err;
|
||||
|
||||
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);
|
||||
|
||||
for (;;) {
|
||||
nilfs_segctor_accept(sci, &req);
|
||||
err = nilfs_segctor_construct(sci, &req);
|
||||
err = nilfs_segctor_construct(sci, SC_LSEG_SR);
|
||||
nilfs_remove_written_gcinodes(nilfs, &sci->sc_gc_inodes);
|
||||
nilfs_segctor_notify(sci, &req);
|
||||
|
||||
if (likely(!err))
|
||||
break;
|
||||
|
@ -2560,6 +2558,16 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
|
|||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
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:
|
||||
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_transaction_info ti;
|
||||
struct nilfs_segctor_req req = { .mode = mode };
|
||||
|
||||
nilfs_transaction_lock(sbi, &ti, 0);
|
||||
|
||||
nilfs_segctor_accept(sci, &req);
|
||||
nilfs_segctor_construct(sci, &req);
|
||||
nilfs_segctor_notify(sci, &req);
|
||||
nilfs_segctor_construct(sci, mode);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
struct nilfs_sc_info *sci = (struct nilfs_sc_info *)arg;
|
||||
struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
|
||||
struct timer_list timer;
|
||||
int timeout = 0;
|
||||
|
||||
|
@ -2680,7 +2685,6 @@ static int nilfs_segctor_thread(void *arg)
|
|||
} else {
|
||||
DEFINE_WAIT(wait);
|
||||
int should_sleep = 1;
|
||||
struct the_nilfs *nilfs;
|
||||
|
||||
prepare_to_wait(&sci->sc_wait_daemon, &wait,
|
||||
TASK_INTERRUPTIBLE);
|
||||
|
@ -2701,8 +2705,8 @@ static int nilfs_segctor_thread(void *arg)
|
|||
finish_wait(&sci->sc_wait_daemon, &wait);
|
||||
timeout = ((sci->sc_state & NILFS_SEGCTOR_COMMIT) &&
|
||||
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);
|
||||
}
|
||||
goto loop;
|
||||
|
@ -2797,12 +2801,9 @@ static void nilfs_segctor_write_out(struct nilfs_sc_info *sci)
|
|||
do {
|
||||
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
||||
struct nilfs_transaction_info ti;
|
||||
struct nilfs_segctor_req req = { .mode = SC_LSEG_SR };
|
||||
|
||||
nilfs_transaction_lock(sbi, &ti, 0);
|
||||
nilfs_segctor_accept(sci, &req);
|
||||
ret = nilfs_segctor_construct(sci, &req);
|
||||
nilfs_segctor_notify(sci, &req);
|
||||
ret = nilfs_segctor_construct(sci, SC_LSEG_SR);
|
||||
nilfs_transaction_unlock(sbi);
|
||||
|
||||
} 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;
|
||||
int err;
|
||||
|
||||
/* Each field of nilfs_segctor is cleared through the initialization
|
||||
of super-block info */
|
||||
if (NILFS_SC(sbi)) {
|
||||
/*
|
||||
* 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);
|
||||
if (!sbi->s_sc_info)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -116,6 +116,7 @@ struct nilfs_segsum_pointer {
|
|||
* @sc_wait_daemon: Daemon wait queue
|
||||
* @sc_wait_task: Start/end wait queue to control segctord task
|
||||
* @sc_seq_request: Request counter
|
||||
* @sc_seq_accept: Accepted request count
|
||||
* @sc_seq_done: Completion counter
|
||||
* @sc_sync: Request of explicit sync operation
|
||||
* @sc_interval: Timeout value of background construction
|
||||
|
@ -169,6 +170,7 @@ struct nilfs_sc_info {
|
|||
wait_queue_head_t sc_wait_task;
|
||||
|
||||
__u32 sc_seq_request;
|
||||
__u32 sc_seq_accepted;
|
||||
__u32 sc_seq_done;
|
||||
|
||||
int sc_sync;
|
||||
|
|
|
@ -96,9 +96,6 @@ void nilfs_error(struct super_block *sb, const char *function,
|
|||
if (!(sb->s_flags & MS_RDONLY)) {
|
||||
struct the_nilfs *nilfs = sbi->s_nilfs;
|
||||
|
||||
if (!nilfs_test_opt(sbi, ERRORS_CONT))
|
||||
nilfs_detach_segment_constructor(sbi);
|
||||
|
||||
down_write(&nilfs->ns_sem);
|
||||
if (!(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);
|
||||
nilfs->ns_sbwtime[1] = t;
|
||||
}
|
||||
sbi->s_super->s_dirt = 0;
|
||||
clear_nilfs_sb_dirty(nilfs);
|
||||
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);
|
||||
|
||||
down_write(&nilfs->ns_sem);
|
||||
if (sb->s_dirt)
|
||||
if (nilfs_sb_dirty(nilfs))
|
||||
nilfs_commit_super(sbi, 1);
|
||||
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");
|
||||
if (nilfs_test_opt(sbi, NORECOVERY))
|
||||
seq_printf(seq, ",norecovery");
|
||||
if (nilfs_test_opt(sbi, DISCARD))
|
||||
seq_printf(seq, ",discard");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -550,7 +549,7 @@ static const struct export_operations nilfs_export_ops = {
|
|||
enum {
|
||||
Opt_err_cont, Opt_err_panic, Opt_err_ro,
|
||||
Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
|
||||
Opt_err,
|
||||
Opt_discard, Opt_err,
|
||||
};
|
||||
|
||||
static match_table_t tokens = {
|
||||
|
@ -561,6 +560,7 @@ static match_table_t tokens = {
|
|||
{Opt_snapshot, "cp=%u"},
|
||||
{Opt_order, "order=%s"},
|
||||
{Opt_norecovery, "norecovery"},
|
||||
{Opt_discard, "discard"},
|
||||
{Opt_err, NULL}
|
||||
};
|
||||
|
||||
|
@ -614,6 +614,9 @@ static int parse_options(char *options, struct super_block *sb)
|
|||
case Opt_norecovery:
|
||||
nilfs_set_opt(sbi, NORECOVERY);
|
||||
break;
|
||||
case Opt_discard:
|
||||
nilfs_set_opt(sbi, DISCARD);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR
|
||||
"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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct inode *dat = nilfs_dat_inode(nilfs);
|
||||
|
|
|
@ -38,6 +38,7 @@ enum {
|
|||
the latest checkpoint was loaded */
|
||||
THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */
|
||||
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(DISCONTINUED, discontinued)
|
||||
THE_NILFS_FNS(GC_RUNNING, gc_running)
|
||||
THE_NILFS_FNS(SB_DIRTY, sb_dirty)
|
||||
|
||||
/* Minimum interval of periodical update of superblocks (in seconds) */
|
||||
#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 *);
|
||||
int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
|
||||
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 *);
|
||||
struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
|
||||
int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int);
|
||||
|
|
|
@ -153,6 +153,7 @@ struct nilfs_super_root {
|
|||
semantics also for data */
|
||||
#define NILFS_MOUNT_NORECOVERY 0x4000 /* Disable write access during
|
||||
mount-time recovery */
|
||||
#define NILFS_MOUNT_DISCARD 0x8000 /* Issue DISCARD requests */
|
||||
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче