static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
struct nilfs_argv *argv, int dir,
ssize_t (*dofunc)(struct the_nilfs *,
- int, int,
+ __u64 *, int,
void *, size_t, size_t))
{
void *buf;
+ void __user *base = (void __user *)(unsigned long)argv->v_base;
size_t maxmembs, total, n;
ssize_t nr;
int ret, i;
+ __u64 pos, ppos;
if (argv->v_nmembs == 0)
return 0;
ret = 0;
total = 0;
+ pos = argv->v_index;
for (i = 0; i < argv->v_nmembs; i += n) {
n = (argv->v_nmembs - i < maxmembs) ?
argv->v_nmembs - i : maxmembs;
if ((dir & _IOC_WRITE) &&
- copy_from_user(buf,
- (void __user *)argv->v_base + argv->v_size * i,
- argv->v_size * n)) {
+ copy_from_user(buf, base + argv->v_size * i,
+ argv->v_size * n)) {
ret = -EFAULT;
break;
}
- nr = (*dofunc)(nilfs, argv->v_index + i, argv->v_flags, buf,
- argv->v_size, n);
+ ppos = pos;
+ nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size,
+ n);
if (nr < 0) {
ret = nr;
break;
}
if ((dir & _IOC_READ) &&
- copy_to_user(
- (void __user *)argv->v_base + argv->v_size * i,
- buf, argv->v_size * nr)) {
+ copy_to_user(base + argv->v_size * i, buf,
+ argv->v_size * nr)) {
ret = -EFAULT;
break;
}
total += nr;
+ if ((size_t)nr < n)
+ break;
+ if (pos == ppos)
+ pos += n;
}
argv->v_nmembs = total;
}
static ssize_t
-nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
- return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, index, flags, buf,
+ return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf,
nmembs);
}
}
static ssize_t
-nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
- return nilfs_sufile_get_suinfo(nilfs->ns_sufile, index, buf, nmembs);
+ return nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs);
}
static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp,
}
static ssize_t
-nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs);
}
static ssize_t
-nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
struct inode *dat = nilfs_dat_inode(nilfs);
}
static ssize_t
-nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
struct inode *inode;
}
static ssize_t
-nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, int index,
+nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, __u64 *posp,
int flags, void *buf, size_t size,
size_t nmembs)
{
}
static ssize_t
-nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, int index, int flags,
+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);
}
static ssize_t
-nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, int index, int flags,
- void *buf, size_t size, size_t nmembs)
+nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp,
+ int flags, void *buf, size_t size,
+ size_t nmembs)
{
struct inode *dat = nilfs_dat_inode(nilfs);
struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
}
static ssize_t
-nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs);
static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
unsigned int cmd, void __user *argp)
{
- int ret;
-
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
-
- ret = nilfs_clean_segments(inode->i_sb, argp);
- clear_nilfs_cond_nongc_write(NILFS_SB(inode->i_sb)->s_nilfs);
- return ret;
-}
-
-static int nilfs_ioctl_test_cond(struct the_nilfs *nilfs, int cond)
-{
- return (cond & NILFS_TIMEDWAIT_SEG_WRITE) &&
- nilfs_cond_nongc_write(nilfs);
-}
-
-static void nilfs_ioctl_clear_cond(struct the_nilfs *nilfs, int cond)
-{
- if (cond & NILFS_TIMEDWAIT_SEG_WRITE)
- clear_nilfs_cond_nongc_write(nilfs);
-}
-
-static int nilfs_ioctl_timedwait(struct inode *inode, struct file *filp,
- unsigned int cmd, void __user *argp)
-{
- struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
- struct nilfs_wait_cond wc;
- long ret;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (copy_from_user(&wc, argp, sizeof(wc)))
- return -EFAULT;
-
- unlock_kernel();
- ret = wc.wc_flags ?
- wait_event_interruptible_timeout(
- nilfs->ns_cleanerd_wq,
- nilfs_ioctl_test_cond(nilfs, wc.wc_cond),
- timespec_to_jiffies(&wc.wc_timeout)) :
- wait_event_interruptible(
- nilfs->ns_cleanerd_wq,
- nilfs_ioctl_test_cond(nilfs, wc.wc_cond));
- lock_kernel();
- nilfs_ioctl_clear_cond(nilfs, wc.wc_cond);
-
- if (ret > 0) {
- jiffies_to_timespec(ret, &wc.wc_timeout);
- if (copy_to_user(argp, &wc, sizeof(wc)))
- return -EFAULT;
- return 0;
- }
- if (ret != 0)
- return -EINTR;
-
- return wc.wc_flags ? -ETIME : 0;
+ return nilfs_clean_segments(inode->i_sb, argp);
}
static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
return 0;
}
-int nilfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = filp->f_dentry->d_inode;
void __user *argp = (void * __user *)arg;
switch (cmd) {
return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp);
case NILFS_IOCTL_CLEAN_SEGMENTS:
return nilfs_ioctl_clean_segments(inode, filp, cmd, argp);
- case NILFS_IOCTL_TIMEDWAIT:
- return nilfs_ioctl_timedwait(inode, filp, cmd, argp);
case NILFS_IOCTL_SYNC:
return nilfs_ioctl_sync(inode, filp, cmd, argp);
default:
return -ENOTTY;
}
}
-
-/* compat_ioctl */
-#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
-
-static int nilfs_compat_locked_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- lock_kernel();
- ret = nilfs_ioctl(inode, filp, cmd, arg);
- unlock_kernel();
- return ret;
-}
-
-static int
-nilfs_compat_ioctl_uargv32_to_uargv(struct nilfs_argv32 __user *uargv32,
- struct nilfs_argv __user *uargv)
-{
- compat_uptr_t base;
- compat_size_t nmembs, size;
- compat_int_t index, flags;
-
- if (get_user(base, &uargv32->v_base) ||
- put_user(compat_ptr(base), &uargv->v_base) ||
- get_user(nmembs, &uargv32->v_nmembs) ||
- put_user(nmembs, &uargv->v_nmembs) ||
- get_user(size, &uargv32->v_size) ||
- put_user(size, &uargv->v_size) ||
- get_user(index, &uargv32->v_index) ||
- put_user(index, &uargv->v_index) ||
- get_user(flags, &uargv32->v_flags) ||
- put_user(flags, &uargv->v_flags))
- return -EFAULT;
- return 0;
-}
-
-static int
-nilfs_compat_ioctl_uargv_to_uargv32(struct nilfs_argv __user *uargv,
- struct nilfs_argv32 __user *uargv32)
-{
- size_t nmembs;
-
- if (get_user(nmembs, &uargv->v_nmembs) ||
- put_user(nmembs, &uargv32->v_nmembs))
- return -EFAULT;
- return 0;
-}
-
-static int
-nilfs_compat_ioctl_get_by_argv(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct nilfs_argv __user *uargv;
- struct nilfs_argv32 __user *uargv32;
- int ret;
-
- uargv = compat_alloc_user_space(sizeof(struct nilfs_argv));
- uargv32 = compat_ptr(arg);
- ret = nilfs_compat_ioctl_uargv32_to_uargv(uargv32, uargv);
- if (ret < 0)
- return ret;
-
- ret = nilfs_compat_locked_ioctl(inode, filp, cmd, (unsigned long)uargv);
- if (ret < 0)
- return ret;
-
- return nilfs_compat_ioctl_uargv_to_uargv32(uargv, uargv32);
-}
-
-static int
-nilfs_compat_ioctl_change_cpmode(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct nilfs_cpmode __user *ucpmode;
- struct nilfs_cpmode32 __user *ucpmode32;
- int mode;
-
- ucpmode = compat_alloc_user_space(sizeof(struct nilfs_cpmode));
- ucpmode32 = compat_ptr(arg);
- if (copy_in_user(&ucpmode->cm_cno, &ucpmode32->cm_cno,
- sizeof(__u64)) ||
- get_user(mode, &ucpmode32->cm_mode) ||
- put_user(mode, &ucpmode->cm_mode))
- return -EFAULT;
-
- return nilfs_compat_locked_ioctl(
- inode, filp, cmd, (unsigned long)ucpmode);
-}
-
-
-static inline int
-nilfs_compat_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- return nilfs_compat_locked_ioctl(inode, filp, cmd, arg);
-}
-
-static inline int
-nilfs_compat_ioctl_get_cpinfo(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg);
-}
-
-static inline int
-nilfs_compat_ioctl_get_cpstat(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- return nilfs_compat_locked_ioctl(inode, filp, cmd, arg);
-}
-
-static inline int
-nilfs_compat_ioctl_get_suinfo(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg);
-}
-
-static int
-nilfs_compat_ioctl_get_sustat(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct nilfs_sustat __user *usustat;
- struct nilfs_sustat32 __user *usustat32;
- time_t ctime, nongc_ctime;
- int ret;
-
- usustat = compat_alloc_user_space(sizeof(struct nilfs_sustat));
- ret = nilfs_compat_locked_ioctl(inode, filp, cmd,
- (unsigned long)usustat);
- if (ret < 0)
- return ret;
-
- usustat32 = compat_ptr(arg);
- if (copy_in_user(&usustat32->ss_nsegs, &usustat->ss_nsegs,
- sizeof(__u64)) ||
- copy_in_user(&usustat32->ss_ncleansegs, &usustat->ss_ncleansegs,
- sizeof(__u64)) ||
- copy_in_user(&usustat32->ss_ndirtysegs, &usustat->ss_ndirtysegs,
- sizeof(__u64)) ||
- get_user(ctime, &usustat->ss_ctime) ||
- put_user(ctime, &usustat32->ss_ctime) ||
- get_user(nongc_ctime, &usustat->ss_nongc_ctime) ||
- put_user(nongc_ctime, &usustat32->ss_nongc_ctime))
- return -EFAULT;
- return 0;
-}
-
-static inline int
-nilfs_compat_ioctl_get_vinfo(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg);
-}
-
-static inline int
-nilfs_compat_ioctl_get_bdescs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg);
-}
-
-static int
-nilfs_compat_ioctl_clean_segments(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct nilfs_argv __user *uargv;
- struct nilfs_argv32 __user *uargv32;
- int i, ret;
-
- uargv = compat_alloc_user_space(sizeof(struct nilfs_argv) * 5);
- uargv32 = compat_ptr(arg);
- for (i = 0; i < 5; i++) {
- ret = nilfs_compat_ioctl_uargv32_to_uargv(&uargv32[i],
- &uargv[i]);
- if (ret < 0)
- return ret;
- }
- return nilfs_compat_locked_ioctl(
- inode, filp, cmd, (unsigned long)uargv);
-}
-
-static int
-nilfs_compat_ioctl_timedwait(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct nilfs_wait_cond __user *uwcond;
- struct nilfs_wait_cond32 __user *uwcond32;
- struct timespec ts;
- int cond, flags, ret;
-
- uwcond = compat_alloc_user_space(sizeof(struct nilfs_wait_cond));
- uwcond32 = compat_ptr(arg);
- if (get_user(cond, &uwcond32->wc_cond) ||
- put_user(cond, &uwcond->wc_cond) ||
- get_user(flags, &uwcond32->wc_flags) ||
- put_user(flags, &uwcond->wc_flags) ||
- get_user(ts.tv_sec, &uwcond32->wc_timeout.tv_sec) ||
- get_user(ts.tv_nsec, &uwcond32->wc_timeout.tv_nsec) ||
- put_user(ts.tv_sec, &uwcond->wc_timeout.tv_sec) ||
- put_user(ts.tv_nsec, &uwcond->wc_timeout.tv_nsec))
- return -EFAULT;
-
- ret = nilfs_compat_locked_ioctl(inode, filp, cmd,
- (unsigned long)uwcond);
- if (ret < 0)
- return ret;
-
- if (get_user(ts.tv_sec, &uwcond->wc_timeout.tv_sec) ||
- get_user(ts.tv_nsec, &uwcond->wc_timeout.tv_nsec) ||
- put_user(ts.tv_sec, &uwcond32->wc_timeout.tv_sec) ||
- put_user(ts.tv_nsec, &uwcond32->wc_timeout.tv_nsec))
- return -EFAULT;
-
- return 0;
-}
-
-static int nilfs_compat_ioctl_sync(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- return nilfs_compat_locked_ioctl(inode, filp, cmd, arg);
-}
-
-long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct inode *inode = filp->f_dentry->d_inode;
-
- switch (cmd) {
- case NILFS_IOCTL32_CHANGE_CPMODE:
- return nilfs_compat_ioctl_change_cpmode(
- inode, filp, NILFS_IOCTL_CHANGE_CPMODE, arg);
- case NILFS_IOCTL_DELETE_CHECKPOINT:
- return nilfs_compat_ioctl_delete_checkpoint(
- inode, filp, cmd, arg);
- case NILFS_IOCTL32_GET_CPINFO:
- return nilfs_compat_ioctl_get_cpinfo(
- inode, filp, NILFS_IOCTL_GET_CPINFO, arg);
- case NILFS_IOCTL_GET_CPSTAT:
- return nilfs_compat_ioctl_get_cpstat(inode, filp, cmd, arg);
- case NILFS_IOCTL32_GET_SUINFO:
- return nilfs_compat_ioctl_get_suinfo(
- inode, filp, NILFS_IOCTL_GET_SUINFO, arg);
- case NILFS_IOCTL32_GET_SUSTAT:
- return nilfs_compat_ioctl_get_sustat(
- inode, filp, NILFS_IOCTL_GET_SUSTAT, arg);
- case NILFS_IOCTL32_GET_VINFO:
- return nilfs_compat_ioctl_get_vinfo(
- inode, filp, NILFS_IOCTL_GET_VINFO, arg);
- case NILFS_IOCTL32_GET_BDESCS:
- return nilfs_compat_ioctl_get_bdescs(
- inode, filp, NILFS_IOCTL_GET_BDESCS, arg);
- case NILFS_IOCTL32_CLEAN_SEGMENTS:
- return nilfs_compat_ioctl_clean_segments(
- inode, filp, NILFS_IOCTL_CLEAN_SEGMENTS, arg);
- case NILFS_IOCTL32_TIMEDWAIT:
- return nilfs_compat_ioctl_timedwait(
- inode, filp, NILFS_IOCTL_TIMEDWAIT, arg);
- case NILFS_IOCTL_SYNC:
- return nilfs_compat_ioctl_sync(inode, filp, cmd, arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-#endif