diff options
Diffstat (limited to 'fs/nilfs2/ioctl.c')
-rw-r--r-- | fs/nilfs2/ioctl.c | 71 |
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); |
132 | out: | ||
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 */ | 163 | out: |
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: | 591 | out_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]); |
595 | out: | ||
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, | |||
618 | long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 649 | long 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: |