ioctl.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /*
  2. * ioctl.c - NILFS ioctl operations.
  3. *
  4. * Copyright (C) 2007, 2008 Nippon Telegraph and Telephone Corporation.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19. *
  20. * Written by Koji Sato <koji@osrg.net>.
  21. */
  22. #include <linux/fs.h>
  23. #include <linux/wait.h>
  24. #include <linux/smp_lock.h> /* lock_kernel(), unlock_kernel() */
  25. #include <linux/capability.h> /* capable() */
  26. #include <linux/uaccess.h> /* copy_from_user(), copy_to_user() */
  27. #include <linux/nilfs2_fs.h>
  28. #include "nilfs.h"
  29. #include "segment.h"
  30. #include "bmap.h"
  31. #include "cpfile.h"
  32. #include "sufile.h"
  33. #include "dat.h"
  34. static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
  35. struct nilfs_argv *argv, int dir,
  36. ssize_t (*dofunc)(struct the_nilfs *,
  37. __u64 *, int,
  38. void *, size_t, size_t))
  39. {
  40. void *buf;
  41. void __user *base = (void __user *)(unsigned long)argv->v_base;
  42. size_t maxmembs, total, n;
  43. ssize_t nr;
  44. int ret, i;
  45. __u64 pos, ppos;
  46. if (argv->v_nmembs == 0)
  47. return 0;
  48. if (argv->v_size > PAGE_SIZE)
  49. return -EINVAL;
  50. buf = (void *)__get_free_pages(GFP_NOFS, 0);
  51. if (unlikely(!buf))
  52. return -ENOMEM;
  53. maxmembs = PAGE_SIZE / argv->v_size;
  54. ret = 0;
  55. total = 0;
  56. pos = argv->v_index;
  57. for (i = 0; i < argv->v_nmembs; i += n) {
  58. n = (argv->v_nmembs - i < maxmembs) ?
  59. argv->v_nmembs - i : maxmembs;
  60. if ((dir & _IOC_WRITE) &&
  61. copy_from_user(buf, base + argv->v_size * i,
  62. argv->v_size * n)) {
  63. ret = -EFAULT;
  64. break;
  65. }
  66. ppos = pos;
  67. nr = dofunc(nilfs, &pos, argv->v_flags, buf, argv->v_size,
  68. n);
  69. if (nr < 0) {
  70. ret = nr;
  71. break;
  72. }
  73. if ((dir & _IOC_READ) &&
  74. copy_to_user(base + argv->v_size * i, buf,
  75. argv->v_size * nr)) {
  76. ret = -EFAULT;
  77. break;
  78. }
  79. total += nr;
  80. if ((size_t)nr < n)
  81. break;
  82. if (pos == ppos)
  83. pos += n;
  84. }
  85. argv->v_nmembs = total;
  86. free_pages((unsigned long)buf, 0);
  87. return ret;
  88. }
  89. static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
  90. unsigned int cmd, void __user *argp)
  91. {
  92. struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile;
  93. struct nilfs_transaction_info ti;
  94. struct nilfs_cpmode cpmode;
  95. int ret;
  96. if (!capable(CAP_SYS_ADMIN))
  97. return -EPERM;
  98. if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
  99. return -EFAULT;
  100. nilfs_transaction_begin(inode->i_sb, &ti, 0);
  101. ret = nilfs_cpfile_change_cpmode(
  102. cpfile, cpmode.cm_cno, cpmode.cm_mode);
  103. if (unlikely(ret < 0)) {
  104. nilfs_transaction_abort(inode->i_sb);
  105. return ret;
  106. }
  107. nilfs_transaction_commit(inode->i_sb); /* never fails */
  108. return ret;
  109. }
  110. static int
  111. nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
  112. unsigned int cmd, void __user *argp)
  113. {
  114. struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile;
  115. struct nilfs_transaction_info ti;
  116. __u64 cno;
  117. int ret;
  118. if (!capable(CAP_SYS_ADMIN))
  119. return -EPERM;
  120. if (copy_from_user(&cno, argp, sizeof(cno)))
  121. return -EFAULT;
  122. nilfs_transaction_begin(inode->i_sb, &ti, 0);
  123. ret = nilfs_cpfile_delete_checkpoint(cpfile, cno);
  124. if (unlikely(ret < 0)) {
  125. nilfs_transaction_abort(inode->i_sb);
  126. return ret;
  127. }
  128. nilfs_transaction_commit(inode->i_sb); /* never fails */
  129. return ret;
  130. }
  131. static ssize_t
  132. nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
  133. void *buf, size_t size, size_t nmembs)
  134. {
  135. return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf,
  136. nmembs);
  137. }
  138. static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp,
  139. unsigned int cmd, void __user *argp)
  140. {
  141. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  142. struct nilfs_argv argv;
  143. int ret;
  144. if (copy_from_user(&argv, argp, sizeof(argv)))
  145. return -EFAULT;
  146. down_read(&nilfs->ns_segctor_sem);
  147. ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
  148. nilfs_ioctl_do_get_cpinfo);
  149. up_read(&nilfs->ns_segctor_sem);
  150. if (ret < 0)
  151. return ret;
  152. if (copy_to_user(argp, &argv, sizeof(argv)))
  153. ret = -EFAULT;
  154. return ret;
  155. }
  156. static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp,
  157. unsigned int cmd, void __user *argp)
  158. {
  159. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  160. struct nilfs_cpstat cpstat;
  161. int ret;
  162. down_read(&nilfs->ns_segctor_sem);
  163. ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat);
  164. up_read(&nilfs->ns_segctor_sem);
  165. if (ret < 0)
  166. return ret;
  167. if (copy_to_user(argp, &cpstat, sizeof(cpstat)))
  168. ret = -EFAULT;
  169. return ret;
  170. }
  171. static ssize_t
  172. nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
  173. void *buf, size_t size, size_t nmembs)
  174. {
  175. return nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs);
  176. }
  177. static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp,
  178. unsigned int cmd, void __user *argp)
  179. {
  180. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  181. struct nilfs_argv argv;
  182. int ret;
  183. if (copy_from_user(&argv, argp, sizeof(argv)))
  184. return -EFAULT;
  185. down_read(&nilfs->ns_segctor_sem);
  186. ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
  187. nilfs_ioctl_do_get_suinfo);
  188. up_read(&nilfs->ns_segctor_sem);
  189. if (ret < 0)
  190. return ret;
  191. if (copy_to_user(argp, &argv, sizeof(argv)))
  192. ret = -EFAULT;
  193. return ret;
  194. }
  195. static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
  196. unsigned int cmd, void __user *argp)
  197. {
  198. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  199. struct nilfs_sustat sustat;
  200. int ret;
  201. down_read(&nilfs->ns_segctor_sem);
  202. ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat);
  203. up_read(&nilfs->ns_segctor_sem);
  204. if (ret < 0)
  205. return ret;
  206. if (copy_to_user(argp, &sustat, sizeof(sustat)))
  207. ret = -EFAULT;
  208. return ret;
  209. }
  210. static ssize_t
  211. nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
  212. void *buf, size_t size, size_t nmembs)
  213. {
  214. return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs);
  215. }
  216. static int nilfs_ioctl_get_vinfo(struct inode *inode, struct file *filp,
  217. unsigned int cmd, void __user *argp)
  218. {
  219. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  220. struct nilfs_argv argv;
  221. int ret;
  222. if (copy_from_user(&argv, argp, sizeof(argv)))
  223. return -EFAULT;
  224. down_read(&nilfs->ns_segctor_sem);
  225. ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
  226. nilfs_ioctl_do_get_vinfo);
  227. up_read(&nilfs->ns_segctor_sem);
  228. if (ret < 0)
  229. return ret;
  230. if (copy_to_user(argp, &argv, sizeof(argv)))
  231. ret = -EFAULT;
  232. return ret;
  233. }
  234. static ssize_t
  235. nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
  236. void *buf, size_t size, size_t nmembs)
  237. {
  238. struct inode *dat = nilfs_dat_inode(nilfs);
  239. struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
  240. struct nilfs_bdesc *bdescs = buf;
  241. int ret, i;
  242. for (i = 0; i < nmembs; i++) {
  243. ret = nilfs_bmap_lookup_at_level(bmap,
  244. bdescs[i].bd_offset,
  245. bdescs[i].bd_level + 1,
  246. &bdescs[i].bd_blocknr);
  247. if (ret < 0) {
  248. if (ret != -ENOENT)
  249. return ret;
  250. bdescs[i].bd_blocknr = 0;
  251. }
  252. }
  253. return nmembs;
  254. }
  255. static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp,
  256. unsigned int cmd, void __user *argp)
  257. {
  258. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  259. struct nilfs_argv argv;
  260. int ret;
  261. if (copy_from_user(&argv, argp, sizeof(argv)))
  262. return -EFAULT;
  263. down_read(&nilfs->ns_segctor_sem);
  264. ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
  265. nilfs_ioctl_do_get_bdescs);
  266. up_read(&nilfs->ns_segctor_sem);
  267. if (ret < 0)
  268. return ret;
  269. if (copy_to_user(argp, &argv, sizeof(argv)))
  270. ret = -EFAULT;
  271. return ret;
  272. }
  273. static int nilfs_ioctl_move_inode_block(struct inode *inode,
  274. struct nilfs_vdesc *vdesc,
  275. struct list_head *buffers)
  276. {
  277. struct buffer_head *bh;
  278. int ret;
  279. if (vdesc->vd_flags == 0)
  280. ret = nilfs_gccache_submit_read_data(
  281. inode, vdesc->vd_offset, vdesc->vd_blocknr,
  282. vdesc->vd_vblocknr, &bh);
  283. else
  284. ret = nilfs_gccache_submit_read_node(
  285. inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh);
  286. if (unlikely(ret < 0)) {
  287. if (ret == -ENOENT)
  288. printk(KERN_CRIT
  289. "%s: invalid virtual block address (%s): "
  290. "ino=%llu, cno=%llu, offset=%llu, "
  291. "blocknr=%llu, vblocknr=%llu\n",
  292. __func__, vdesc->vd_flags ? "node" : "data",
  293. (unsigned long long)vdesc->vd_ino,
  294. (unsigned long long)vdesc->vd_cno,
  295. (unsigned long long)vdesc->vd_offset,
  296. (unsigned long long)vdesc->vd_blocknr,
  297. (unsigned long long)vdesc->vd_vblocknr);
  298. return ret;
  299. }
  300. bh->b_private = vdesc;
  301. list_add_tail(&bh->b_assoc_buffers, buffers);
  302. return 0;
  303. }
  304. static ssize_t
  305. nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, __u64 *posp, int flags,
  306. void *buf, size_t size, size_t nmembs)
  307. {
  308. struct inode *inode;
  309. struct nilfs_vdesc *vdesc;
  310. struct buffer_head *bh, *n;
  311. LIST_HEAD(buffers);
  312. ino_t ino;
  313. __u64 cno;
  314. int i, ret;
  315. for (i = 0, vdesc = buf; i < nmembs; ) {
  316. ino = vdesc->vd_ino;
  317. cno = vdesc->vd_cno;
  318. inode = nilfs_gc_iget(nilfs, ino, cno);
  319. if (unlikely(inode == NULL)) {
  320. ret = -ENOMEM;
  321. goto failed;
  322. }
  323. do {
  324. ret = nilfs_ioctl_move_inode_block(inode, vdesc,
  325. &buffers);
  326. if (unlikely(ret < 0))
  327. goto failed;
  328. vdesc++;
  329. } while (++i < nmembs &&
  330. vdesc->vd_ino == ino && vdesc->vd_cno == cno);
  331. }
  332. list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
  333. ret = nilfs_gccache_wait_and_mark_dirty(bh);
  334. if (unlikely(ret < 0)) {
  335. if (ret == -EEXIST) {
  336. vdesc = bh->b_private;
  337. printk(KERN_CRIT
  338. "%s: conflicting %s buffer: "
  339. "ino=%llu, cno=%llu, offset=%llu, "
  340. "blocknr=%llu, vblocknr=%llu\n",
  341. __func__,
  342. vdesc->vd_flags ? "node" : "data",
  343. (unsigned long long)vdesc->vd_ino,
  344. (unsigned long long)vdesc->vd_cno,
  345. (unsigned long long)vdesc->vd_offset,
  346. (unsigned long long)vdesc->vd_blocknr,
  347. (unsigned long long)vdesc->vd_vblocknr);
  348. }
  349. goto failed;
  350. }
  351. list_del_init(&bh->b_assoc_buffers);
  352. bh->b_private = NULL;
  353. brelse(bh);
  354. }
  355. return nmembs;
  356. failed:
  357. list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
  358. list_del_init(&bh->b_assoc_buffers);
  359. bh->b_private = NULL;
  360. brelse(bh);
  361. }
  362. return ret;
  363. }
  364. static inline int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
  365. struct nilfs_argv *argv,
  366. int dir)
  367. {
  368. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  369. nilfs_ioctl_do_move_blocks);
  370. }
  371. static ssize_t
  372. nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, __u64 *posp,
  373. int flags, void *buf, size_t size,
  374. size_t nmembs)
  375. {
  376. struct inode *cpfile = nilfs->ns_cpfile;
  377. struct nilfs_period *periods = buf;
  378. int ret, i;
  379. for (i = 0; i < nmembs; i++) {
  380. ret = nilfs_cpfile_delete_checkpoints(
  381. cpfile, periods[i].p_start, periods[i].p_end);
  382. if (ret < 0)
  383. return ret;
  384. }
  385. return nmembs;
  386. }
  387. static inline int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs,
  388. struct nilfs_argv *argv,
  389. int dir)
  390. {
  391. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  392. nilfs_ioctl_do_delete_checkpoints);
  393. }
  394. static ssize_t
  395. nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, __u64 *posp, int flags,
  396. void *buf, size_t size, size_t nmembs)
  397. {
  398. int ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs);
  399. return (ret < 0) ? ret : nmembs;
  400. }
  401. static inline int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
  402. struct nilfs_argv *argv,
  403. int dir)
  404. {
  405. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  406. nilfs_ioctl_do_free_vblocknrs);
  407. }
  408. static ssize_t
  409. nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp,
  410. int flags, void *buf, size_t size,
  411. size_t nmembs)
  412. {
  413. struct inode *dat = nilfs_dat_inode(nilfs);
  414. struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
  415. struct nilfs_bdesc *bdescs = buf;
  416. int ret, i;
  417. for (i = 0; i < nmembs; i++) {
  418. /* XXX: use macro or inline func to check liveness */
  419. ret = nilfs_bmap_lookup_at_level(bmap,
  420. bdescs[i].bd_offset,
  421. bdescs[i].bd_level + 1,
  422. &bdescs[i].bd_blocknr);
  423. if (ret < 0) {
  424. if (ret != -ENOENT)
  425. return ret;
  426. bdescs[i].bd_blocknr = 0;
  427. }
  428. if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr)
  429. /* skip dead block */
  430. continue;
  431. if (bdescs[i].bd_level == 0) {
  432. ret = nilfs_mdt_mark_block_dirty(dat,
  433. bdescs[i].bd_offset);
  434. if (ret < 0) {
  435. WARN_ON(ret == -ENOENT);
  436. return ret;
  437. }
  438. } else {
  439. ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset,
  440. bdescs[i].bd_level);
  441. if (ret < 0) {
  442. WARN_ON(ret == -ENOENT);
  443. return ret;
  444. }
  445. }
  446. }
  447. return nmembs;
  448. }
  449. static inline int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
  450. struct nilfs_argv *argv,
  451. int dir)
  452. {
  453. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  454. nilfs_ioctl_do_mark_blocks_dirty);
  455. }
  456. static ssize_t
  457. nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags,
  458. void *buf, size_t size, size_t nmembs)
  459. {
  460. struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs);
  461. int ret;
  462. if (unlikely(!sbi))
  463. return -EROFS;
  464. ret = nilfs_segctor_add_segments_to_be_freed(
  465. NILFS_SC(sbi), buf, nmembs);
  466. nilfs_put_writer(nilfs);
  467. return (ret < 0) ? ret : nmembs;
  468. }
  469. static inline int nilfs_ioctl_free_segments(struct the_nilfs *nilfs,
  470. struct nilfs_argv *argv,
  471. int dir)
  472. {
  473. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  474. nilfs_ioctl_do_free_segments);
  475. }
  476. int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
  477. void __user *argp)
  478. {
  479. struct nilfs_argv argv[5];
  480. const char *msg;
  481. int dir, ret;
  482. if (copy_from_user(argv, argp, sizeof(argv)))
  483. return -EFAULT;
  484. dir = _IOC_WRITE;
  485. ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], dir);
  486. if (ret < 0) {
  487. msg = "cannot read source blocks";
  488. goto failed;
  489. }
  490. ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], dir);
  491. if (ret < 0) {
  492. /*
  493. * can safely abort because checkpoints can be removed
  494. * independently.
  495. */
  496. msg = "cannot delete checkpoints";
  497. goto failed;
  498. }
  499. ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], dir);
  500. if (ret < 0) {
  501. /*
  502. * can safely abort because DAT file is updated atomically
  503. * using a copy-on-write technique.
  504. */
  505. msg = "cannot delete virtual blocks from DAT file";
  506. goto failed;
  507. }
  508. ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], dir);
  509. if (ret < 0) {
  510. /*
  511. * can safely abort because the operation is nondestructive.
  512. */
  513. msg = "cannot mark copying blocks dirty";
  514. goto failed;
  515. }
  516. ret = nilfs_ioctl_free_segments(nilfs, &argv[4], dir);
  517. if (ret < 0) {
  518. /*
  519. * can safely abort because this operation is atomic.
  520. */
  521. msg = "cannot set segments to be freed";
  522. goto failed;
  523. }
  524. return 0;
  525. failed:
  526. nilfs_remove_all_gcinode(nilfs);
  527. printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n",
  528. msg, ret);
  529. return ret;
  530. }
  531. static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
  532. unsigned int cmd, void __user *argp)
  533. {
  534. if (!capable(CAP_SYS_ADMIN))
  535. return -EPERM;
  536. return nilfs_clean_segments(inode->i_sb, argp);
  537. }
  538. static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
  539. unsigned int cmd, void __user *argp)
  540. {
  541. __u64 cno;
  542. int ret;
  543. ret = nilfs_construct_segment(inode->i_sb);
  544. if (ret < 0)
  545. return ret;
  546. if (argp != NULL) {
  547. cno = NILFS_SB(inode->i_sb)->s_nilfs->ns_cno - 1;
  548. if (copy_to_user(argp, &cno, sizeof(cno)))
  549. return -EFAULT;
  550. }
  551. return 0;
  552. }
  553. long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  554. {
  555. struct inode *inode = filp->f_dentry->d_inode;
  556. void __user *argp = (void * __user *)arg;
  557. switch (cmd) {
  558. case NILFS_IOCTL_CHANGE_CPMODE:
  559. return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp);
  560. case NILFS_IOCTL_DELETE_CHECKPOINT:
  561. return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp);
  562. case NILFS_IOCTL_GET_CPINFO:
  563. return nilfs_ioctl_get_cpinfo(inode, filp, cmd, argp);
  564. case NILFS_IOCTL_GET_CPSTAT:
  565. return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp);
  566. case NILFS_IOCTL_GET_SUINFO:
  567. return nilfs_ioctl_get_suinfo(inode, filp, cmd, argp);
  568. case NILFS_IOCTL_GET_SUSTAT:
  569. return nilfs_ioctl_get_sustat(inode, filp, cmd, argp);
  570. case NILFS_IOCTL_GET_VINFO:
  571. /* XXX: rename to ??? */
  572. return nilfs_ioctl_get_vinfo(inode, filp, cmd, argp);
  573. case NILFS_IOCTL_GET_BDESCS:
  574. return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp);
  575. case NILFS_IOCTL_CLEAN_SEGMENTS:
  576. return nilfs_ioctl_clean_segments(inode, filp, cmd, argp);
  577. case NILFS_IOCTL_SYNC:
  578. return nilfs_ioctl_sync(inode, filp, cmd, argp);
  579. default:
  580. return -ENOTTY;
  581. }
  582. }