diff options
-rw-r--r-- | Documentation/filesystems/nilfs2.txt | 7 | ||||
-rw-r--r-- | fs/nilfs2/ioctl.c | 92 | ||||
-rw-r--r-- | include/linux/nilfs2_fs.h | 2 |
3 files changed, 101 insertions, 0 deletions
diff --git a/Documentation/filesystems/nilfs2.txt b/Documentation/filesystems/nilfs2.txt index 06887d46ccf2..8b887ae4e39e 100644 --- a/Documentation/filesystems/nilfs2.txt +++ b/Documentation/filesystems/nilfs2.txt | |||
@@ -111,6 +111,13 @@ Table of NILFS2 specific ioctls | |||
111 | nilfs_resize utilities and by nilfs_cleanerd | 111 | nilfs_resize utilities and by nilfs_cleanerd |
112 | daemon. | 112 | daemon. |
113 | 113 | ||
114 | NILFS_IOCTL_SET_SUINFO Modify segment usage info of requested | ||
115 | segments. This ioctl is used by | ||
116 | nilfs_cleanerd daemon to skip unnecessary | ||
117 | cleaning operation of segments and reduce | ||
118 | performance penalty or wear of flash device | ||
119 | due to redundant move of in-use blocks. | ||
120 | |||
114 | NILFS_IOCTL_GET_SUSTAT Return segment usage statistics. This ioctl | 121 | NILFS_IOCTL_GET_SUSTAT Return segment usage statistics. This ioctl |
115 | is used in lssu, nilfs_resize utilities and | 122 | is used in lssu, nilfs_resize utilities and |
116 | by nilfs_cleanerd daemon. | 123 | by nilfs_cleanerd daemon. |
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 2b34021948e4..c19a23158487 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
@@ -1163,6 +1163,95 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, | |||
1163 | return ret; | 1163 | return ret; |
1164 | } | 1164 | } |
1165 | 1165 | ||
1166 | /** | ||
1167 | * nilfs_ioctl_set_suinfo - set segment usage info | ||
1168 | * @inode: inode object | ||
1169 | * @filp: file object | ||
1170 | * @cmd: ioctl's request code | ||
1171 | * @argp: pointer on argument from userspace | ||
1172 | * | ||
1173 | * Description: Expects an array of nilfs_suinfo_update structures | ||
1174 | * encapsulated in nilfs_argv and updates the segment usage info | ||
1175 | * according to the flags in nilfs_suinfo_update. | ||
1176 | * | ||
1177 | * Return Value: On success, 0 is returned. On error, one of the | ||
1178 | * following negative error codes is returned. | ||
1179 | * | ||
1180 | * %-EPERM - Not enough permissions | ||
1181 | * | ||
1182 | * %-EFAULT - Error copying input data | ||
1183 | * | ||
1184 | * %-EIO - I/O error. | ||
1185 | * | ||
1186 | * %-ENOMEM - Insufficient amount of memory available. | ||
1187 | * | ||
1188 | * %-EINVAL - Invalid values in input (segment number, flags or nblocks) | ||
1189 | */ | ||
1190 | static int nilfs_ioctl_set_suinfo(struct inode *inode, struct file *filp, | ||
1191 | unsigned int cmd, void __user *argp) | ||
1192 | { | ||
1193 | struct the_nilfs *nilfs = inode->i_sb->s_fs_info; | ||
1194 | struct nilfs_transaction_info ti; | ||
1195 | struct nilfs_argv argv; | ||
1196 | size_t len; | ||
1197 | void __user *base; | ||
1198 | void *kbuf; | ||
1199 | int ret; | ||
1200 | |||
1201 | if (!capable(CAP_SYS_ADMIN)) | ||
1202 | return -EPERM; | ||
1203 | |||
1204 | ret = mnt_want_write_file(filp); | ||
1205 | if (ret) | ||
1206 | return ret; | ||
1207 | |||
1208 | ret = -EFAULT; | ||
1209 | if (copy_from_user(&argv, argp, sizeof(argv))) | ||
1210 | goto out; | ||
1211 | |||
1212 | ret = -EINVAL; | ||
1213 | if (argv.v_size < sizeof(struct nilfs_suinfo_update)) | ||
1214 | goto out; | ||
1215 | |||
1216 | if (argv.v_nmembs > nilfs->ns_nsegments) | ||
1217 | goto out; | ||
1218 | |||
1219 | if (argv.v_nmembs >= UINT_MAX / argv.v_size) | ||
1220 | goto out; | ||
1221 | |||
1222 | len = argv.v_size * argv.v_nmembs; | ||
1223 | if (!len) { | ||
1224 | ret = 0; | ||
1225 | goto out; | ||
1226 | } | ||
1227 | |||
1228 | base = (void __user *)(unsigned long)argv.v_base; | ||
1229 | kbuf = vmalloc(len); | ||
1230 | if (!kbuf) { | ||
1231 | ret = -ENOMEM; | ||
1232 | goto out; | ||
1233 | } | ||
1234 | |||
1235 | if (copy_from_user(kbuf, base, len)) { | ||
1236 | ret = -EFAULT; | ||
1237 | goto out_free; | ||
1238 | } | ||
1239 | |||
1240 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | ||
1241 | ret = nilfs_sufile_set_suinfo(nilfs->ns_sufile, kbuf, argv.v_size, | ||
1242 | argv.v_nmembs); | ||
1243 | if (unlikely(ret < 0)) | ||
1244 | nilfs_transaction_abort(inode->i_sb); | ||
1245 | else | ||
1246 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | ||
1247 | |||
1248 | out_free: | ||
1249 | vfree(kbuf); | ||
1250 | out: | ||
1251 | mnt_drop_write_file(filp); | ||
1252 | return ret; | ||
1253 | } | ||
1254 | |||
1166 | long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 1255 | long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
1167 | { | 1256 | { |
1168 | struct inode *inode = file_inode(filp); | 1257 | struct inode *inode = file_inode(filp); |
@@ -1189,6 +1278,8 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
1189 | return nilfs_ioctl_get_info(inode, filp, cmd, argp, | 1278 | return nilfs_ioctl_get_info(inode, filp, cmd, argp, |
1190 | sizeof(struct nilfs_suinfo), | 1279 | sizeof(struct nilfs_suinfo), |
1191 | nilfs_ioctl_do_get_suinfo); | 1280 | nilfs_ioctl_do_get_suinfo); |
1281 | case NILFS_IOCTL_SET_SUINFO: | ||
1282 | return nilfs_ioctl_set_suinfo(inode, filp, cmd, argp); | ||
1192 | case NILFS_IOCTL_GET_SUSTAT: | 1283 | case NILFS_IOCTL_GET_SUSTAT: |
1193 | return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); | 1284 | return nilfs_ioctl_get_sustat(inode, filp, cmd, argp); |
1194 | case NILFS_IOCTL_GET_VINFO: | 1285 | case NILFS_IOCTL_GET_VINFO: |
@@ -1228,6 +1319,7 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
1228 | case NILFS_IOCTL_GET_CPINFO: | 1319 | case NILFS_IOCTL_GET_CPINFO: |
1229 | case NILFS_IOCTL_GET_CPSTAT: | 1320 | case NILFS_IOCTL_GET_CPSTAT: |
1230 | case NILFS_IOCTL_GET_SUINFO: | 1321 | case NILFS_IOCTL_GET_SUINFO: |
1322 | case NILFS_IOCTL_SET_SUINFO: | ||
1231 | case NILFS_IOCTL_GET_SUSTAT: | 1323 | case NILFS_IOCTL_GET_SUSTAT: |
1232 | case NILFS_IOCTL_GET_VINFO: | 1324 | case NILFS_IOCTL_GET_VINFO: |
1233 | case NILFS_IOCTL_GET_BDESCS: | 1325 | case NILFS_IOCTL_GET_BDESCS: |
diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h index 252657874a19..1fb465f9baf2 100644 --- a/include/linux/nilfs2_fs.h +++ b/include/linux/nilfs2_fs.h | |||
@@ -905,5 +905,7 @@ struct nilfs_bdesc { | |||
905 | _IOW(NILFS_IOCTL_IDENT, 0x8B, __u64) | 905 | _IOW(NILFS_IOCTL_IDENT, 0x8B, __u64) |
906 | #define NILFS_IOCTL_SET_ALLOC_RANGE \ | 906 | #define NILFS_IOCTL_SET_ALLOC_RANGE \ |
907 | _IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2]) | 907 | _IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2]) |
908 | #define NILFS_IOCTL_SET_SUINFO \ | ||
909 | _IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv) | ||
908 | 910 | ||
909 | #endif /* _LINUX_NILFS_FS_H */ | 911 | #endif /* _LINUX_NILFS_FS_H */ |