Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 144903
b: refs/heads/master
c: 4f6b828
h: refs/heads/master
i:
  144901: 7fe693d
  144899: 02d6d13
  144895: 81d0291
v: v3
  • Loading branch information
Ryusuke Konishi committed May 11, 2009
1 parent 84380dc commit 2ecdc67
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 75 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 47eb6b9c8fa963c9f49967ad1d9d7ec947d15b68
refs/heads/master: 4f6b828837b4e3836f2c9ac2f0eab9773b6c1327
163 changes: 93 additions & 70 deletions trunk/fs/nilfs2/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/smp_lock.h> /* lock_kernel(), unlock_kernel() */
#include <linux/capability.h> /* capable() */
#include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */
#include <linux/vmalloc.h>
#include <linux/nilfs2_fs.h>
#include "nilfs.h"
#include "segment.h"
Expand Down Expand Up @@ -297,10 +298,10 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode,
return 0;
}

static ssize_t
nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
struct nilfs_argv *argv, void *buf)
{
size_t nmembs = argv->v_nmembs;
struct inode *inode;
struct nilfs_vdesc *vdesc;
struct buffer_head *bh, *n;
Expand Down Expand Up @@ -361,19 +362,10 @@ nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, __u64 *posp, int flags,
return ret;
}

static inline int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
struct nilfs_argv *argv,
int dir)
{
return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
nilfs_ioctl_do_move_blocks);
}

static ssize_t
nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, __u64 *posp,
int flags, void *buf, size_t size,
size_t nmembs)
static int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs,
struct nilfs_argv *argv, void *buf)
{
size_t nmembs = argv->v_nmembs;
struct inode *cpfile = nilfs->ns_cpfile;
struct nilfs_period *periods = buf;
int ret, i;
Expand All @@ -387,36 +379,21 @@ nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, __u64 *posp,
return nmembs;
}

static inline int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs,
struct nilfs_argv *argv,
int dir)
static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
struct nilfs_argv *argv, void *buf)
{
return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
nilfs_ioctl_do_delete_checkpoints);
}
size_t nmembs = argv->v_nmembs;
int ret;

static ssize_t
nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
int ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs);
ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs);

return (ret < 0) ? ret : nmembs;
}

static inline int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
struct nilfs_argv *argv,
int dir)
{
return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
nilfs_ioctl_do_free_vblocknrs);
}

static ssize_t
nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp,
int flags, void *buf, size_t size,
size_t nmembs)
static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
struct nilfs_argv *argv, void *buf)
{
size_t nmembs = argv->v_nmembs;
struct inode *dat = nilfs_dat_inode(nilfs);
struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
struct nilfs_bdesc *bdescs = buf;
Expand Down Expand Up @@ -455,18 +432,10 @@ nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp,
return nmembs;
}

static inline int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
struct nilfs_argv *argv,
int dir)
{
return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
nilfs_ioctl_do_mark_blocks_dirty);
}

static ssize_t
nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
static int nilfs_ioctl_free_segments(struct the_nilfs *nilfs,
struct nilfs_argv *argv, void *buf)
{
size_t nmembs = argv->v_nmembs;
struct nilfs_sb_info *sbi = nilfs->ns_writer;
int ret;

Expand All @@ -481,31 +450,19 @@ nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags,
return (ret < 0) ? ret : nmembs;
}

static inline int nilfs_ioctl_free_segments(struct the_nilfs *nilfs,
struct nilfs_argv *argv,
int dir)
{
return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
nilfs_ioctl_do_free_segments);
}

int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
void __user *argp)
struct nilfs_argv *argv, void **kbufs)
{
struct nilfs_argv argv[5];
const char *msg;
int dir, ret;

if (copy_from_user(argv, argp, sizeof(argv)))
return -EFAULT;
int ret;

dir = _IOC_WRITE;
ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], dir);
ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]);
if (ret < 0) {
msg = "cannot read source blocks";
goto failed;
}
ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], dir);

ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], kbufs[1]);
if (ret < 0) {
/*
* can safely abort because checkpoints can be removed
Expand All @@ -514,7 +471,7 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
msg = "cannot delete checkpoints";
goto failed;
}
ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], dir);
ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], kbufs[2]);
if (ret < 0) {
/*
* can safely abort because DAT file is updated atomically
Expand All @@ -523,15 +480,15 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
msg = "cannot delete virtual blocks from DAT file";
goto failed;
}
ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], dir);
ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], kbufs[3]);
if (ret < 0) {
/*
* can safely abort because the operation is nondestructive.
*/
msg = "cannot mark copying blocks dirty";
goto failed;
}
ret = nilfs_ioctl_free_segments(nilfs, &argv[4], dir);
ret = nilfs_ioctl_free_segments(nilfs, &argv[4], kbufs[4]);
if (ret < 0) {
/*
* can safely abort because this operation is atomic.
Expand All @@ -551,9 +508,75 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
unsigned int cmd, void __user *argp)
{
struct nilfs_argv argv[5];
const static size_t argsz[5] = {
sizeof(struct nilfs_vdesc),
sizeof(struct nilfs_period),
sizeof(__u64),
sizeof(struct nilfs_bdesc),
sizeof(__u64),
};
void __user *base;
void *kbufs[5];
struct the_nilfs *nilfs;
size_t len, nsegs;
int n, ret;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return nilfs_clean_segments(inode->i_sb, argp);

if (copy_from_user(argv, argp, sizeof(argv)))
return -EFAULT;

nsegs = argv[4].v_nmembs;
if (argv[4].v_size != argsz[4])
return -EINVAL;
/*
* 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]);

nilfs = NILFS_SB(inode->i_sb)->s_nilfs;

for (n = 0; n < 4; n++) {
ret = -EINVAL;
if (argv[n].v_size != argsz[n])
goto out_free;

if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment)
goto out_free;

len = argv[n].v_size * argv[n].v_nmembs;
base = (void __user *)(unsigned long)argv[n].v_base;
if (len == 0) {
kbufs[n] = NULL;
continue;
}

kbufs[n] = vmalloc(len);
if (!kbufs[n]) {
ret = -ENOMEM;
goto out_free;
}
if (copy_from_user(kbufs[n], base, len)) {
ret = -EFAULT;
vfree(kbufs[n]);
goto out_free;
}
}

ret = nilfs_clean_segments(inode->i_sb, argv, kbufs);

out_free:
while (--n > 0)
vfree(kbufs[n]);
kfree(kbufs[4]);
return ret;
}

static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
Expand Down
3 changes: 2 additions & 1 deletion trunk/fs/nilfs2/nilfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ extern int nilfs_sync_file(struct file *, struct dentry *, int);

/* ioctl.c */
long nilfs_ioctl(struct file *, unsigned int, unsigned long);
int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, void __user *);
int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, struct nilfs_argv *,
void **);

/* inode.c */
extern struct inode *nilfs_new_inode(struct inode *, int);
Expand Down
5 changes: 3 additions & 2 deletions trunk/fs/nilfs2/segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -2589,7 +2589,8 @@ nilfs_remove_written_gcinodes(struct the_nilfs *nilfs, struct list_head *head)
}
}

int nilfs_clean_segments(struct super_block *sb, void __user *argp)
int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
void **kbufs)
{
struct nilfs_sb_info *sbi = NILFS_SB(sb);
struct nilfs_sc_info *sci = NILFS_SC(sbi);
Expand All @@ -2606,7 +2607,7 @@ int nilfs_clean_segments(struct super_block *sb, void __user *argp)
err = nilfs_init_gcdat_inode(nilfs);
if (unlikely(err))
goto out_unlock;
err = nilfs_ioctl_prepare_clean_segments(nilfs, argp);
err = nilfs_ioctl_prepare_clean_segments(nilfs, argv, kbufs);
if (unlikely(err))
goto out_unlock;

Expand Down
3 changes: 2 additions & 1 deletion trunk/fs/nilfs2/segment.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ extern int nilfs_construct_segment(struct super_block *);
extern int nilfs_construct_dsync_segment(struct super_block *, struct inode *,
loff_t, loff_t);
extern void nilfs_flush_segment(struct super_block *, ino_t);
extern int nilfs_clean_segments(struct super_block *, void __user *);
extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *,
void **);

extern int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *,
__u64 *, size_t);
Expand Down

0 comments on commit 2ecdc67

Please sign in to comment.