Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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
  • Loading branch information
torvalds committed Mar 3, 2010
2 parents eca281a + 0d561f1 commit feaf77d
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 116 deletions.
3 changes: 3 additions & 0 deletions Documentation/filesystems/nilfs2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
============
Expand Down
3 changes: 1 addition & 2 deletions fs/nilfs2/dat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
66 changes: 48 additions & 18 deletions fs/nilfs2/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -496,22 +512,30 @@ static int nilfs_ioctl_clean_segments(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(argv, argp, sizeof(argv)))
return -EFAULT;
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
* segment numbers is enough small.
*/
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++) {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}
Expand Down
41 changes: 11 additions & 30 deletions fs/nilfs2/recovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand All @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
18 changes: 18 additions & 0 deletions fs/nilfs2/segbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 1 addition & 4 deletions fs/nilfs2/segbuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit feaf77d

Please sign in to comment.