aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/nilfs2.txt7
-rw-r--r--fs/nilfs2/ioctl.c92
-rw-r--r--include/linux/nilfs2_fs.h2
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 */
1190static 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
1248out_free:
1249 vfree(kbuf);
1250out:
1251 mnt_drop_write_file(filp);
1252 return ret;
1253}
1254
1166long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 1255long 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 */