aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nilfs2/ioctl.c')
-rw-r--r--fs/nilfs2/ioctl.c71
1 files changed, 51 insertions, 20 deletions
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index f6af76042d80..f90a33d9a5b0 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -23,9 +23,11 @@
23#include <linux/fs.h> 23#include <linux/fs.h>
24#include <linux/wait.h> 24#include <linux/wait.h>
25#include <linux/smp_lock.h> /* lock_kernel(), unlock_kernel() */ 25#include <linux/smp_lock.h> /* lock_kernel(), unlock_kernel() */
26#include <linux/slab.h>
26#include <linux/capability.h> /* capable() */ 27#include <linux/capability.h> /* capable() */
27#include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ 28#include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */
28#include <linux/vmalloc.h> 29#include <linux/vmalloc.h>
30#include <linux/mount.h> /* mnt_want_write(), mnt_drop_write() */
29#include <linux/nilfs2_fs.h> 31#include <linux/nilfs2_fs.h>
30#include "nilfs.h" 32#include "nilfs.h"
31#include "segment.h" 33#include "segment.h"
@@ -107,20 +109,28 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
107 109
108 if (!capable(CAP_SYS_ADMIN)) 110 if (!capable(CAP_SYS_ADMIN))
109 return -EPERM; 111 return -EPERM;
112
113 ret = mnt_want_write(filp->f_path.mnt);
114 if (ret)
115 return ret;
116
117 ret = -EFAULT;
110 if (copy_from_user(&cpmode, argp, sizeof(cpmode))) 118 if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
111 return -EFAULT; 119 goto out;
112 120
113 mutex_lock(&nilfs->ns_mount_mutex); 121 mutex_lock(&nilfs->ns_mount_mutex);
122
114 nilfs_transaction_begin(inode->i_sb, &ti, 0); 123 nilfs_transaction_begin(inode->i_sb, &ti, 0);
115 ret = nilfs_cpfile_change_cpmode( 124 ret = nilfs_cpfile_change_cpmode(
116 cpfile, cpmode.cm_cno, cpmode.cm_mode); 125 cpfile, cpmode.cm_cno, cpmode.cm_mode);
117 if (unlikely(ret < 0)) { 126 if (unlikely(ret < 0))
118 nilfs_transaction_abort(inode->i_sb); 127 nilfs_transaction_abort(inode->i_sb);
119 mutex_unlock(&nilfs->ns_mount_mutex); 128 else
120 return ret; 129 nilfs_transaction_commit(inode->i_sb); /* never fails */
121 } 130
122 nilfs_transaction_commit(inode->i_sb); /* never fails */
123 mutex_unlock(&nilfs->ns_mount_mutex); 131 mutex_unlock(&nilfs->ns_mount_mutex);
132out:
133 mnt_drop_write(filp->f_path.mnt);
124 return ret; 134 return ret;
125} 135}
126 136
@@ -135,16 +145,23 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
135 145
136 if (!capable(CAP_SYS_ADMIN)) 146 if (!capable(CAP_SYS_ADMIN))
137 return -EPERM; 147 return -EPERM;
148
149 ret = mnt_want_write(filp->f_path.mnt);
150 if (ret)
151 return ret;
152
153 ret = -EFAULT;
138 if (copy_from_user(&cno, argp, sizeof(cno))) 154 if (copy_from_user(&cno, argp, sizeof(cno)))
139 return -EFAULT; 155 goto out;
140 156
141 nilfs_transaction_begin(inode->i_sb, &ti, 0); 157 nilfs_transaction_begin(inode->i_sb, &ti, 0);
142 ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); 158 ret = nilfs_cpfile_delete_checkpoint(cpfile, cno);
143 if (unlikely(ret < 0)) { 159 if (unlikely(ret < 0))
144 nilfs_transaction_abort(inode->i_sb); 160 nilfs_transaction_abort(inode->i_sb);
145 return ret; 161 else
146 } 162 nilfs_transaction_commit(inode->i_sb); /* never fails */
147 nilfs_transaction_commit(inode->i_sb); /* never fails */ 163out:
164 mnt_drop_write(filp->f_path.mnt);
148 return ret; 165 return ret;
149} 166}
150 167
@@ -480,7 +497,7 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
480 unsigned int cmd, void __user *argp) 497 unsigned int cmd, void __user *argp)
481{ 498{
482 struct nilfs_argv argv[5]; 499 struct nilfs_argv argv[5];
483 const static size_t argsz[5] = { 500 static const size_t argsz[5] = {
484 sizeof(struct nilfs_vdesc), 501 sizeof(struct nilfs_vdesc),
485 sizeof(struct nilfs_period), 502 sizeof(struct nilfs_period),
486 sizeof(__u64), 503 sizeof(__u64),
@@ -496,12 +513,19 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
496 if (!capable(CAP_SYS_ADMIN)) 513 if (!capable(CAP_SYS_ADMIN))
497 return -EPERM; 514 return -EPERM;
498 515
516 ret = mnt_want_write(filp->f_path.mnt);
517 if (ret)
518 return ret;
519
520 ret = -EFAULT;
499 if (copy_from_user(argv, argp, sizeof(argv))) 521 if (copy_from_user(argv, argp, sizeof(argv)))
500 return -EFAULT; 522 goto out;
501 523
524 ret = -EINVAL;
502 nsegs = argv[4].v_nmembs; 525 nsegs = argv[4].v_nmembs;
503 if (argv[4].v_size != argsz[4]) 526 if (argv[4].v_size != argsz[4])
504 return -EINVAL; 527 goto out;
528
505 /* 529 /*
506 * argv[4] points to segment numbers this ioctl cleans. We 530 * argv[4] points to segment numbers this ioctl cleans. We
507 * use kmalloc() for its buffer because memory used for the 531 * use kmalloc() for its buffer because memory used for the
@@ -509,9 +533,10 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
509 */ 533 */
510 kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, 534 kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base,
511 nsegs * sizeof(__u64)); 535 nsegs * sizeof(__u64));
512 if (IS_ERR(kbufs[4])) 536 if (IS_ERR(kbufs[4])) {
513 return PTR_ERR(kbufs[4]); 537 ret = PTR_ERR(kbufs[4]);
514 538 goto out;
539 }
515 nilfs = NILFS_SB(inode->i_sb)->s_nilfs; 540 nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
516 541
517 for (n = 0; n < 4; n++) { 542 for (n = 0; n < 4; n++) {
@@ -563,10 +588,12 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
563 nilfs_remove_all_gcinode(nilfs); 588 nilfs_remove_all_gcinode(nilfs);
564 clear_nilfs_gc_running(nilfs); 589 clear_nilfs_gc_running(nilfs);
565 590
566 out_free: 591out_free:
567 while (--n >= 0) 592 while (--n >= 0)
568 vfree(kbufs[n]); 593 vfree(kbufs[n]);
569 kfree(kbufs[4]); 594 kfree(kbufs[4]);
595out:
596 mnt_drop_write(filp->f_path.mnt);
570 return ret; 597 return ret;
571} 598}
572 599
@@ -575,13 +602,17 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
575{ 602{
576 __u64 cno; 603 __u64 cno;
577 int ret; 604 int ret;
605 struct the_nilfs *nilfs;
578 606
579 ret = nilfs_construct_segment(inode->i_sb); 607 ret = nilfs_construct_segment(inode->i_sb);
580 if (ret < 0) 608 if (ret < 0)
581 return ret; 609 return ret;
582 610
583 if (argp != NULL) { 611 if (argp != NULL) {
584 cno = NILFS_SB(inode->i_sb)->s_nilfs->ns_cno - 1; 612 nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
613 down_read(&nilfs->ns_segctor_sem);
614 cno = nilfs->ns_cno - 1;
615 up_read(&nilfs->ns_segctor_sem);
585 if (copy_to_user(argp, &cno, sizeof(cno))) 616 if (copy_to_user(argp, &cno, sizeof(cno)))
586 return -EFAULT; 617 return -EFAULT;
587 } 618 }
@@ -618,7 +649,7 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
618long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 649long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
619{ 650{
620 struct inode *inode = filp->f_dentry->d_inode; 651 struct inode *inode = filp->f_dentry->d_inode;
621 void __user *argp = (void * __user *)arg; 652 void __user *argp = (void __user *)arg;
622 653
623 switch (cmd) { 654 switch (cmd) {
624 case NILFS_IOCTL_CHANGE_CPMODE: 655 case NILFS_IOCTL_CHANGE_CPMODE: