diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-01-25 23:59:40 -0500 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-02-12 22:26:02 -0500 |
commit | 7512487e6d6459e4c3f9c7cedc53050a6c30e387 (patch) | |
tree | a2f7ed0a787be5ccd3bcd92b6e9f2f3e4eb3267b /fs | |
parent | e902ec9906e844f4613fa6190c6fa65f162dc86e (diff) |
nilfs2: use mnt_want_write in ioctls where write access is needed
A few nilfs2 ioctls need to ask for and then later release write
access to the mount in order to avoid potential write to read-only
mounts.
This adds the missing mnt_want_write and mnt_drop_write in
nilfs_ioctl_change_cpmode, nilfs_ioctl_delete_checkpoint, and
nilfs_ioctl_clean_segments.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nilfs2/ioctl.c | 60 |
1 files changed, 43 insertions, 17 deletions
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index d6b2b83de363..8e5cad020c30 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/capability.h> /* capable() */ | 26 | #include <linux/capability.h> /* capable() */ |
27 | #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ | 27 | #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */ |
28 | #include <linux/vmalloc.h> | 28 | #include <linux/vmalloc.h> |
29 | #include <linux/mount.h> /* mnt_want_write(), mnt_drop_write() */ | ||
29 | #include <linux/nilfs2_fs.h> | 30 | #include <linux/nilfs2_fs.h> |
30 | #include "nilfs.h" | 31 | #include "nilfs.h" |
31 | #include "segment.h" | 32 | #include "segment.h" |
@@ -107,20 +108,28 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, | |||
107 | 108 | ||
108 | if (!capable(CAP_SYS_ADMIN)) | 109 | if (!capable(CAP_SYS_ADMIN)) |
109 | return -EPERM; | 110 | return -EPERM; |
111 | |||
112 | ret = mnt_want_write(filp->f_path.mnt); | ||
113 | if (ret) | ||
114 | return ret; | ||
115 | |||
116 | ret = -EFAULT; | ||
110 | if (copy_from_user(&cpmode, argp, sizeof(cpmode))) | 117 | if (copy_from_user(&cpmode, argp, sizeof(cpmode))) |
111 | return -EFAULT; | 118 | goto out; |
112 | 119 | ||
113 | mutex_lock(&nilfs->ns_mount_mutex); | 120 | mutex_lock(&nilfs->ns_mount_mutex); |
121 | |||
114 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 122 | nilfs_transaction_begin(inode->i_sb, &ti, 0); |
115 | ret = nilfs_cpfile_change_cpmode( | 123 | ret = nilfs_cpfile_change_cpmode( |
116 | cpfile, cpmode.cm_cno, cpmode.cm_mode); | 124 | cpfile, cpmode.cm_cno, cpmode.cm_mode); |
117 | if (unlikely(ret < 0)) { | 125 | if (unlikely(ret < 0)) |
118 | nilfs_transaction_abort(inode->i_sb); | 126 | nilfs_transaction_abort(inode->i_sb); |
119 | mutex_unlock(&nilfs->ns_mount_mutex); | 127 | else |
120 | return ret; | 128 | nilfs_transaction_commit(inode->i_sb); /* never fails */ |
121 | } | 129 | |
122 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | ||
123 | mutex_unlock(&nilfs->ns_mount_mutex); | 130 | mutex_unlock(&nilfs->ns_mount_mutex); |
131 | out: | ||
132 | mnt_drop_write(filp->f_path.mnt); | ||
124 | return ret; | 133 | return ret; |
125 | } | 134 | } |
126 | 135 | ||
@@ -135,16 +144,23 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp, | |||
135 | 144 | ||
136 | if (!capable(CAP_SYS_ADMIN)) | 145 | if (!capable(CAP_SYS_ADMIN)) |
137 | return -EPERM; | 146 | return -EPERM; |
147 | |||
148 | ret = mnt_want_write(filp->f_path.mnt); | ||
149 | if (ret) | ||
150 | return ret; | ||
151 | |||
152 | ret = -EFAULT; | ||
138 | if (copy_from_user(&cno, argp, sizeof(cno))) | 153 | if (copy_from_user(&cno, argp, sizeof(cno))) |
139 | return -EFAULT; | 154 | goto out; |
140 | 155 | ||
141 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 156 | nilfs_transaction_begin(inode->i_sb, &ti, 0); |
142 | ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); | 157 | ret = nilfs_cpfile_delete_checkpoint(cpfile, cno); |
143 | if (unlikely(ret < 0)) { | 158 | if (unlikely(ret < 0)) |
144 | nilfs_transaction_abort(inode->i_sb); | 159 | nilfs_transaction_abort(inode->i_sb); |
145 | return ret; | 160 | else |
146 | } | 161 | nilfs_transaction_commit(inode->i_sb); /* never fails */ |
147 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | 162 | out: |
163 | mnt_drop_write(filp->f_path.mnt); | ||
148 | return ret; | 164 | return ret; |
149 | } | 165 | } |
150 | 166 | ||
@@ -496,12 +512,19 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
496 | if (!capable(CAP_SYS_ADMIN)) | 512 | if (!capable(CAP_SYS_ADMIN)) |
497 | return -EPERM; | 513 | return -EPERM; |
498 | 514 | ||
515 | ret = mnt_want_write(filp->f_path.mnt); | ||
516 | if (ret) | ||
517 | return ret; | ||
518 | |||
519 | ret = -EFAULT; | ||
499 | if (copy_from_user(argv, argp, sizeof(argv))) | 520 | if (copy_from_user(argv, argp, sizeof(argv))) |
500 | return -EFAULT; | 521 | goto out; |
501 | 522 | ||
523 | ret = -EINVAL; | ||
502 | nsegs = argv[4].v_nmembs; | 524 | nsegs = argv[4].v_nmembs; |
503 | if (argv[4].v_size != argsz[4]) | 525 | if (argv[4].v_size != argsz[4]) |
504 | return -EINVAL; | 526 | goto out; |
527 | |||
505 | /* | 528 | /* |
506 | * argv[4] points to segment numbers this ioctl cleans. We | 529 | * argv[4] points to segment numbers this ioctl cleans. We |
507 | * use kmalloc() for its buffer because memory used for the | 530 | * use kmalloc() for its buffer because memory used for the |
@@ -509,9 +532,10 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
509 | */ | 532 | */ |
510 | kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, | 533 | kbufs[4] = memdup_user((void __user *)(unsigned long)argv[4].v_base, |
511 | nsegs * sizeof(__u64)); | 534 | nsegs * sizeof(__u64)); |
512 | if (IS_ERR(kbufs[4])) | 535 | if (IS_ERR(kbufs[4])) { |
513 | return PTR_ERR(kbufs[4]); | 536 | ret = PTR_ERR(kbufs[4]); |
514 | 537 | goto out; | |
538 | } | ||
515 | nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | 539 | nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
516 | 540 | ||
517 | for (n = 0; n < 4; n++) { | 541 | for (n = 0; n < 4; n++) { |
@@ -563,10 +587,12 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
563 | nilfs_remove_all_gcinode(nilfs); | 587 | nilfs_remove_all_gcinode(nilfs); |
564 | clear_nilfs_gc_running(nilfs); | 588 | clear_nilfs_gc_running(nilfs); |
565 | 589 | ||
566 | out_free: | 590 | out_free: |
567 | while (--n >= 0) | 591 | while (--n >= 0) |
568 | vfree(kbufs[n]); | 592 | vfree(kbufs[n]); |
569 | kfree(kbufs[4]); | 593 | kfree(kbufs[4]); |
594 | out: | ||
595 | mnt_drop_write(filp->f_path.mnt); | ||
570 | return ret; | 596 | return ret; |
571 | } | 597 | } |
572 | 598 | ||