ioctl.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  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. int, int,
  38. void *, size_t, size_t))
  39. {
  40. void *buf;
  41. size_t maxmembs, total, n;
  42. ssize_t nr;
  43. int ret, i;
  44. if (argv->v_nmembs == 0)
  45. return 0;
  46. if (argv->v_size > PAGE_SIZE)
  47. return -EINVAL;
  48. buf = (void *)__get_free_pages(GFP_NOFS, 0);
  49. if (unlikely(!buf))
  50. return -ENOMEM;
  51. maxmembs = PAGE_SIZE / argv->v_size;
  52. ret = 0;
  53. total = 0;
  54. for (i = 0; i < argv->v_nmembs; i += n) {
  55. n = (argv->v_nmembs - i < maxmembs) ?
  56. argv->v_nmembs - i : maxmembs;
  57. if ((dir & _IOC_WRITE) &&
  58. copy_from_user(buf,
  59. (void __user *)argv->v_base + argv->v_size * i,
  60. argv->v_size * n)) {
  61. ret = -EFAULT;
  62. break;
  63. }
  64. nr = (*dofunc)(nilfs, argv->v_index + i, argv->v_flags, buf,
  65. argv->v_size, n);
  66. if (nr < 0) {
  67. ret = nr;
  68. break;
  69. }
  70. if ((dir & _IOC_READ) &&
  71. copy_to_user(
  72. (void __user *)argv->v_base + argv->v_size * i,
  73. buf, argv->v_size * nr)) {
  74. ret = -EFAULT;
  75. break;
  76. }
  77. total += nr;
  78. }
  79. argv->v_nmembs = total;
  80. free_pages((unsigned long)buf, 0);
  81. return ret;
  82. }
  83. static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
  84. unsigned int cmd, void __user *argp)
  85. {
  86. struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile;
  87. struct nilfs_transaction_info ti;
  88. struct nilfs_cpmode cpmode;
  89. int ret;
  90. if (!capable(CAP_SYS_ADMIN))
  91. return -EPERM;
  92. if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
  93. return -EFAULT;
  94. nilfs_transaction_begin(inode->i_sb, &ti, 0);
  95. ret = nilfs_cpfile_change_cpmode(
  96. cpfile, cpmode.cm_cno, cpmode.cm_mode);
  97. if (unlikely(ret < 0)) {
  98. nilfs_transaction_abort(inode->i_sb);
  99. return ret;
  100. }
  101. nilfs_transaction_commit(inode->i_sb); /* never fails */
  102. return ret;
  103. }
  104. static int
  105. nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
  106. unsigned int cmd, void __user *argp)
  107. {
  108. struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile;
  109. struct nilfs_transaction_info ti;
  110. __u64 cno;
  111. int ret;
  112. if (!capable(CAP_SYS_ADMIN))
  113. return -EPERM;
  114. if (copy_from_user(&cno, argp, sizeof(cno)))
  115. return -EFAULT;
  116. nilfs_transaction_begin(inode->i_sb, &ti, 0);
  117. ret = nilfs_cpfile_delete_checkpoint(cpfile, cno);
  118. if (unlikely(ret < 0)) {
  119. nilfs_transaction_abort(inode->i_sb);
  120. return ret;
  121. }
  122. nilfs_transaction_commit(inode->i_sb); /* never fails */
  123. return ret;
  124. }
  125. static ssize_t
  126. nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, int index, int flags,
  127. void *buf, size_t size, size_t nmembs)
  128. {
  129. return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, index, flags, buf,
  130. nmembs);
  131. }
  132. static int nilfs_ioctl_get_cpinfo(struct inode *inode, struct file *filp,
  133. unsigned int cmd, void __user *argp)
  134. {
  135. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  136. struct nilfs_argv argv;
  137. int ret;
  138. if (copy_from_user(&argv, argp, sizeof(argv)))
  139. return -EFAULT;
  140. down_read(&nilfs->ns_segctor_sem);
  141. ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
  142. nilfs_ioctl_do_get_cpinfo);
  143. up_read(&nilfs->ns_segctor_sem);
  144. if (ret < 0)
  145. return ret;
  146. if (copy_to_user(argp, &argv, sizeof(argv)))
  147. ret = -EFAULT;
  148. return ret;
  149. }
  150. static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp,
  151. unsigned int cmd, void __user *argp)
  152. {
  153. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  154. struct nilfs_cpstat cpstat;
  155. int ret;
  156. down_read(&nilfs->ns_segctor_sem);
  157. ret = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat);
  158. up_read(&nilfs->ns_segctor_sem);
  159. if (ret < 0)
  160. return ret;
  161. if (copy_to_user(argp, &cpstat, sizeof(cpstat)))
  162. ret = -EFAULT;
  163. return ret;
  164. }
  165. static ssize_t
  166. nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, int index, int flags,
  167. void *buf, size_t size, size_t nmembs)
  168. {
  169. return nilfs_sufile_get_suinfo(nilfs->ns_sufile, index, buf, nmembs);
  170. }
  171. static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp,
  172. unsigned int cmd, void __user *argp)
  173. {
  174. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  175. struct nilfs_argv argv;
  176. int ret;
  177. if (copy_from_user(&argv, argp, sizeof(argv)))
  178. return -EFAULT;
  179. down_read(&nilfs->ns_segctor_sem);
  180. ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
  181. nilfs_ioctl_do_get_suinfo);
  182. up_read(&nilfs->ns_segctor_sem);
  183. if (ret < 0)
  184. return ret;
  185. if (copy_to_user(argp, &argv, sizeof(argv)))
  186. ret = -EFAULT;
  187. return ret;
  188. }
  189. static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
  190. unsigned int cmd, void __user *argp)
  191. {
  192. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  193. struct nilfs_sustat sustat;
  194. int ret;
  195. down_read(&nilfs->ns_segctor_sem);
  196. ret = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat);
  197. up_read(&nilfs->ns_segctor_sem);
  198. if (ret < 0)
  199. return ret;
  200. if (copy_to_user(argp, &sustat, sizeof(sustat)))
  201. ret = -EFAULT;
  202. return ret;
  203. }
  204. static ssize_t
  205. nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, int index, int flags,
  206. void *buf, size_t size, size_t nmembs)
  207. {
  208. return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs);
  209. }
  210. static int nilfs_ioctl_get_vinfo(struct inode *inode, struct file *filp,
  211. unsigned int cmd, void __user *argp)
  212. {
  213. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  214. struct nilfs_argv argv;
  215. int ret;
  216. if (copy_from_user(&argv, argp, sizeof(argv)))
  217. return -EFAULT;
  218. down_read(&nilfs->ns_segctor_sem);
  219. ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
  220. nilfs_ioctl_do_get_vinfo);
  221. up_read(&nilfs->ns_segctor_sem);
  222. if (ret < 0)
  223. return ret;
  224. if (copy_to_user(argp, &argv, sizeof(argv)))
  225. ret = -EFAULT;
  226. return ret;
  227. }
  228. static ssize_t
  229. nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, int index, int flags,
  230. void *buf, size_t size, size_t nmembs)
  231. {
  232. struct inode *dat = nilfs_dat_inode(nilfs);
  233. struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
  234. struct nilfs_bdesc *bdescs = buf;
  235. int ret, i;
  236. for (i = 0; i < nmembs; i++) {
  237. ret = nilfs_bmap_lookup_at_level(bmap,
  238. bdescs[i].bd_offset,
  239. bdescs[i].bd_level + 1,
  240. &bdescs[i].bd_blocknr);
  241. if (ret < 0) {
  242. if (ret != -ENOENT)
  243. return ret;
  244. bdescs[i].bd_blocknr = 0;
  245. }
  246. }
  247. return nmembs;
  248. }
  249. static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp,
  250. unsigned int cmd, void __user *argp)
  251. {
  252. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  253. struct nilfs_argv argv;
  254. int ret;
  255. if (copy_from_user(&argv, argp, sizeof(argv)))
  256. return -EFAULT;
  257. down_read(&nilfs->ns_segctor_sem);
  258. ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd),
  259. nilfs_ioctl_do_get_bdescs);
  260. up_read(&nilfs->ns_segctor_sem);
  261. if (ret < 0)
  262. return ret;
  263. if (copy_to_user(argp, &argv, sizeof(argv)))
  264. ret = -EFAULT;
  265. return ret;
  266. }
  267. static int nilfs_ioctl_move_inode_block(struct inode *inode,
  268. struct nilfs_vdesc *vdesc,
  269. struct list_head *buffers)
  270. {
  271. struct buffer_head *bh;
  272. int ret;
  273. if (vdesc->vd_flags == 0)
  274. ret = nilfs_gccache_submit_read_data(
  275. inode, vdesc->vd_offset, vdesc->vd_blocknr,
  276. vdesc->vd_vblocknr, &bh);
  277. else
  278. ret = nilfs_gccache_submit_read_node(
  279. inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh);
  280. if (unlikely(ret < 0)) {
  281. if (ret == -ENOENT)
  282. printk(KERN_CRIT
  283. "%s: invalid virtual block address (%s): "
  284. "ino=%llu, cno=%llu, offset=%llu, "
  285. "blocknr=%llu, vblocknr=%llu\n",
  286. __func__, vdesc->vd_flags ? "node" : "data",
  287. (unsigned long long)vdesc->vd_ino,
  288. (unsigned long long)vdesc->vd_cno,
  289. (unsigned long long)vdesc->vd_offset,
  290. (unsigned long long)vdesc->vd_blocknr,
  291. (unsigned long long)vdesc->vd_vblocknr);
  292. return ret;
  293. }
  294. bh->b_private = vdesc;
  295. list_add_tail(&bh->b_assoc_buffers, buffers);
  296. return 0;
  297. }
  298. static ssize_t
  299. nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, int index, int flags,
  300. void *buf, size_t size, size_t nmembs)
  301. {
  302. struct inode *inode;
  303. struct nilfs_vdesc *vdesc;
  304. struct buffer_head *bh, *n;
  305. LIST_HEAD(buffers);
  306. ino_t ino;
  307. __u64 cno;
  308. int i, ret;
  309. for (i = 0, vdesc = buf; i < nmembs; ) {
  310. ino = vdesc->vd_ino;
  311. cno = vdesc->vd_cno;
  312. inode = nilfs_gc_iget(nilfs, ino, cno);
  313. if (unlikely(inode == NULL)) {
  314. ret = -ENOMEM;
  315. goto failed;
  316. }
  317. do {
  318. ret = nilfs_ioctl_move_inode_block(inode, vdesc,
  319. &buffers);
  320. if (unlikely(ret < 0))
  321. goto failed;
  322. vdesc++;
  323. } while (++i < nmembs &&
  324. vdesc->vd_ino == ino && vdesc->vd_cno == cno);
  325. }
  326. list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
  327. ret = nilfs_gccache_wait_and_mark_dirty(bh);
  328. if (unlikely(ret < 0)) {
  329. if (ret == -EEXIST) {
  330. vdesc = bh->b_private;
  331. printk(KERN_CRIT
  332. "%s: conflicting %s buffer: "
  333. "ino=%llu, cno=%llu, offset=%llu, "
  334. "blocknr=%llu, vblocknr=%llu\n",
  335. __func__,
  336. vdesc->vd_flags ? "node" : "data",
  337. (unsigned long long)vdesc->vd_ino,
  338. (unsigned long long)vdesc->vd_cno,
  339. (unsigned long long)vdesc->vd_offset,
  340. (unsigned long long)vdesc->vd_blocknr,
  341. (unsigned long long)vdesc->vd_vblocknr);
  342. }
  343. goto failed;
  344. }
  345. list_del_init(&bh->b_assoc_buffers);
  346. bh->b_private = NULL;
  347. brelse(bh);
  348. }
  349. return nmembs;
  350. failed:
  351. list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) {
  352. list_del_init(&bh->b_assoc_buffers);
  353. bh->b_private = NULL;
  354. brelse(bh);
  355. }
  356. return ret;
  357. }
  358. static inline int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
  359. struct nilfs_argv *argv,
  360. int dir)
  361. {
  362. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  363. nilfs_ioctl_do_move_blocks);
  364. }
  365. static ssize_t
  366. nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, int index,
  367. int flags, void *buf, size_t size,
  368. size_t nmembs)
  369. {
  370. struct inode *cpfile = nilfs->ns_cpfile;
  371. struct nilfs_period *periods = buf;
  372. int ret, i;
  373. for (i = 0; i < nmembs; i++) {
  374. ret = nilfs_cpfile_delete_checkpoints(
  375. cpfile, periods[i].p_start, periods[i].p_end);
  376. if (ret < 0)
  377. return ret;
  378. }
  379. return nmembs;
  380. }
  381. static inline int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs,
  382. struct nilfs_argv *argv,
  383. int dir)
  384. {
  385. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  386. nilfs_ioctl_do_delete_checkpoints);
  387. }
  388. static ssize_t
  389. nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, int index, int flags,
  390. void *buf, size_t size, size_t nmembs)
  391. {
  392. int ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs);
  393. return (ret < 0) ? ret : nmembs;
  394. }
  395. static inline int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
  396. struct nilfs_argv *argv,
  397. int dir)
  398. {
  399. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  400. nilfs_ioctl_do_free_vblocknrs);
  401. }
  402. static ssize_t
  403. nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, int index, int flags,
  404. void *buf, size_t size, size_t nmembs)
  405. {
  406. struct inode *dat = nilfs_dat_inode(nilfs);
  407. struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
  408. struct nilfs_bdesc *bdescs = buf;
  409. int ret, i;
  410. for (i = 0; i < nmembs; i++) {
  411. /* XXX: use macro or inline func to check liveness */
  412. ret = nilfs_bmap_lookup_at_level(bmap,
  413. bdescs[i].bd_offset,
  414. bdescs[i].bd_level + 1,
  415. &bdescs[i].bd_blocknr);
  416. if (ret < 0) {
  417. if (ret != -ENOENT)
  418. return ret;
  419. bdescs[i].bd_blocknr = 0;
  420. }
  421. if (bdescs[i].bd_blocknr != bdescs[i].bd_oblocknr)
  422. /* skip dead block */
  423. continue;
  424. if (bdescs[i].bd_level == 0) {
  425. ret = nilfs_mdt_mark_block_dirty(dat,
  426. bdescs[i].bd_offset);
  427. if (ret < 0) {
  428. BUG_ON(ret == -ENOENT);
  429. return ret;
  430. }
  431. } else {
  432. ret = nilfs_bmap_mark(bmap, bdescs[i].bd_offset,
  433. bdescs[i].bd_level);
  434. if (ret < 0) {
  435. BUG_ON(ret == -ENOENT);
  436. return ret;
  437. }
  438. }
  439. }
  440. return nmembs;
  441. }
  442. static inline int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
  443. struct nilfs_argv *argv,
  444. int dir)
  445. {
  446. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  447. nilfs_ioctl_do_mark_blocks_dirty);
  448. }
  449. static ssize_t
  450. nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, int index, int flags,
  451. void *buf, size_t size, size_t nmembs)
  452. {
  453. struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs);
  454. int ret;
  455. BUG_ON(!sbi);
  456. ret = nilfs_segctor_add_segments_to_be_freed(
  457. NILFS_SC(sbi), buf, nmembs);
  458. nilfs_put_writer(nilfs);
  459. return (ret < 0) ? ret : nmembs;
  460. }
  461. static inline int nilfs_ioctl_free_segments(struct the_nilfs *nilfs,
  462. struct nilfs_argv *argv,
  463. int dir)
  464. {
  465. return nilfs_ioctl_wrap_copy(nilfs, argv, dir,
  466. nilfs_ioctl_do_free_segments);
  467. }
  468. int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
  469. void __user *argp)
  470. {
  471. struct nilfs_argv argv[5];
  472. int dir, ret;
  473. if (copy_from_user(argv, argp, sizeof(argv)))
  474. return -EFAULT;
  475. dir = _IOC_WRITE;
  476. ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], dir);
  477. if (ret < 0)
  478. goto out_move_blks;
  479. ret = nilfs_ioctl_delete_checkpoints(nilfs, &argv[1], dir);
  480. if (ret < 0)
  481. goto out_del_cps;
  482. ret = nilfs_ioctl_free_vblocknrs(nilfs, &argv[2], dir);
  483. if (ret < 0)
  484. goto out_free_vbns;
  485. ret = nilfs_ioctl_mark_blocks_dirty(nilfs, &argv[3], dir);
  486. if (ret < 0)
  487. goto out_free_vbns;
  488. ret = nilfs_ioctl_free_segments(nilfs, &argv[4], dir);
  489. if (ret < 0)
  490. goto out_free_segs;
  491. return 0;
  492. out_free_segs:
  493. BUG(); /* XXX: not implemented yet */
  494. out_free_vbns:
  495. BUG();/* XXX: not implemented yet */
  496. out_del_cps:
  497. BUG();/* XXX: not implemented yet */
  498. out_move_blks:
  499. nilfs_remove_all_gcinode(nilfs);
  500. return ret;
  501. }
  502. static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
  503. unsigned int cmd, void __user *argp)
  504. {
  505. int ret;
  506. if (!capable(CAP_SYS_ADMIN))
  507. return -EPERM;
  508. ret = nilfs_clean_segments(inode->i_sb, argp);
  509. clear_nilfs_cond_nongc_write(NILFS_SB(inode->i_sb)->s_nilfs);
  510. return ret;
  511. }
  512. static int nilfs_ioctl_test_cond(struct the_nilfs *nilfs, int cond)
  513. {
  514. return (cond & NILFS_TIMEDWAIT_SEG_WRITE) &&
  515. nilfs_cond_nongc_write(nilfs);
  516. }
  517. static void nilfs_ioctl_clear_cond(struct the_nilfs *nilfs, int cond)
  518. {
  519. if (cond & NILFS_TIMEDWAIT_SEG_WRITE)
  520. clear_nilfs_cond_nongc_write(nilfs);
  521. }
  522. static int nilfs_ioctl_timedwait(struct inode *inode, struct file *filp,
  523. unsigned int cmd, void __user *argp)
  524. {
  525. struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
  526. struct nilfs_wait_cond wc;
  527. long ret;
  528. if (!capable(CAP_SYS_ADMIN))
  529. return -EPERM;
  530. if (copy_from_user(&wc, argp, sizeof(wc)))
  531. return -EFAULT;
  532. unlock_kernel();
  533. ret = wc.wc_flags ?
  534. wait_event_interruptible_timeout(
  535. nilfs->ns_cleanerd_wq,
  536. nilfs_ioctl_test_cond(nilfs, wc.wc_cond),
  537. timespec_to_jiffies(&wc.wc_timeout)) :
  538. wait_event_interruptible(
  539. nilfs->ns_cleanerd_wq,
  540. nilfs_ioctl_test_cond(nilfs, wc.wc_cond));
  541. lock_kernel();
  542. nilfs_ioctl_clear_cond(nilfs, wc.wc_cond);
  543. if (ret > 0) {
  544. jiffies_to_timespec(ret, &wc.wc_timeout);
  545. if (copy_to_user(argp, &wc, sizeof(wc)))
  546. return -EFAULT;
  547. return 0;
  548. }
  549. if (ret != 0)
  550. return -EINTR;
  551. return wc.wc_flags ? -ETIME : 0;
  552. }
  553. static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
  554. unsigned int cmd, void __user *argp)
  555. {
  556. __u64 cno;
  557. int ret;
  558. ret = nilfs_construct_segment(inode->i_sb);
  559. if (ret < 0)
  560. return ret;
  561. if (argp != NULL) {
  562. cno = NILFS_SB(inode->i_sb)->s_nilfs->ns_cno - 1;
  563. if (copy_to_user(argp, &cno, sizeof(cno)))
  564. return -EFAULT;
  565. }
  566. return 0;
  567. }
  568. int nilfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
  569. unsigned long arg)
  570. {
  571. void __user *argp = (void * __user *)arg;
  572. switch (cmd) {
  573. case NILFS_IOCTL_CHANGE_CPMODE:
  574. return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp);
  575. case NILFS_IOCTL_DELETE_CHECKPOINT:
  576. return nilfs_ioctl_delete_checkpoint(inode, filp, cmd, argp);
  577. case NILFS_IOCTL_GET_CPINFO:
  578. return nilfs_ioctl_get_cpinfo(inode, filp, cmd, argp);
  579. case NILFS_IOCTL_GET_CPSTAT:
  580. return nilfs_ioctl_get_cpstat(inode, filp, cmd, argp);
  581. case NILFS_IOCTL_GET_SUINFO:
  582. return nilfs_ioctl_get_suinfo(inode, filp, cmd, argp);
  583. case NILFS_IOCTL_GET_SUSTAT:
  584. return nilfs_ioctl_get_sustat(inode, filp, cmd, argp);
  585. case NILFS_IOCTL_GET_VINFO:
  586. /* XXX: rename to ??? */
  587. return nilfs_ioctl_get_vinfo(inode, filp, cmd, argp);
  588. case NILFS_IOCTL_GET_BDESCS:
  589. return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp);
  590. case NILFS_IOCTL_CLEAN_SEGMENTS:
  591. return nilfs_ioctl_clean_segments(inode, filp, cmd, argp);
  592. case NILFS_IOCTL_TIMEDWAIT:
  593. return nilfs_ioctl_timedwait(inode, filp, cmd, argp);
  594. case NILFS_IOCTL_SYNC:
  595. return nilfs_ioctl_sync(inode, filp, cmd, argp);
  596. default:
  597. return -ENOTTY;
  598. }
  599. }
  600. /* compat_ioctl */
  601. #ifdef CONFIG_COMPAT
  602. #include <linux/compat.h>
  603. static int nilfs_compat_locked_ioctl(struct inode *inode, struct file *filp,
  604. unsigned int cmd, unsigned long arg)
  605. {
  606. int ret;
  607. lock_kernel();
  608. ret = nilfs_ioctl(inode, filp, cmd, arg);
  609. unlock_kernel();
  610. return ret;
  611. }
  612. static int
  613. nilfs_compat_ioctl_uargv32_to_uargv(struct nilfs_argv32 __user *uargv32,
  614. struct nilfs_argv __user *uargv)
  615. {
  616. compat_uptr_t base;
  617. compat_size_t nmembs, size;
  618. compat_int_t index, flags;
  619. if (get_user(base, &uargv32->v_base) ||
  620. put_user(compat_ptr(base), &uargv->v_base) ||
  621. get_user(nmembs, &uargv32->v_nmembs) ||
  622. put_user(nmembs, &uargv->v_nmembs) ||
  623. get_user(size, &uargv32->v_size) ||
  624. put_user(size, &uargv->v_size) ||
  625. get_user(index, &uargv32->v_index) ||
  626. put_user(index, &uargv->v_index) ||
  627. get_user(flags, &uargv32->v_flags) ||
  628. put_user(flags, &uargv->v_flags))
  629. return -EFAULT;
  630. return 0;
  631. }
  632. static int
  633. nilfs_compat_ioctl_uargv_to_uargv32(struct nilfs_argv __user *uargv,
  634. struct nilfs_argv32 __user *uargv32)
  635. {
  636. size_t nmembs;
  637. if (get_user(nmembs, &uargv->v_nmembs) ||
  638. put_user(nmembs, &uargv32->v_nmembs))
  639. return -EFAULT;
  640. return 0;
  641. }
  642. static int
  643. nilfs_compat_ioctl_get_by_argv(struct inode *inode, struct file *filp,
  644. unsigned int cmd, unsigned long arg)
  645. {
  646. struct nilfs_argv __user *uargv;
  647. struct nilfs_argv32 __user *uargv32;
  648. int ret;
  649. uargv = compat_alloc_user_space(sizeof(struct nilfs_argv));
  650. uargv32 = compat_ptr(arg);
  651. ret = nilfs_compat_ioctl_uargv32_to_uargv(uargv32, uargv);
  652. if (ret < 0)
  653. return ret;
  654. ret = nilfs_compat_locked_ioctl(inode, filp, cmd, (unsigned long)uargv);
  655. if (ret < 0)
  656. return ret;
  657. return nilfs_compat_ioctl_uargv_to_uargv32(uargv, uargv32);
  658. }
  659. static int
  660. nilfs_compat_ioctl_change_cpmode(struct inode *inode, struct file *filp,
  661. unsigned int cmd, unsigned long arg)
  662. {
  663. struct nilfs_cpmode __user *ucpmode;
  664. struct nilfs_cpmode32 __user *ucpmode32;
  665. int mode;
  666. ucpmode = compat_alloc_user_space(sizeof(struct nilfs_cpmode));
  667. ucpmode32 = compat_ptr(arg);
  668. if (copy_in_user(&ucpmode->cm_cno, &ucpmode32->cm_cno,
  669. sizeof(__u64)) ||
  670. get_user(mode, &ucpmode32->cm_mode) ||
  671. put_user(mode, &ucpmode->cm_mode))
  672. return -EFAULT;
  673. return nilfs_compat_locked_ioctl(
  674. inode, filp, cmd, (unsigned long)ucpmode);
  675. }
  676. static inline int
  677. nilfs_compat_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
  678. unsigned int cmd, unsigned long arg)
  679. {
  680. return nilfs_compat_locked_ioctl(inode, filp, cmd, arg);
  681. }
  682. static inline int
  683. nilfs_compat_ioctl_get_cpinfo(struct inode *inode, struct file *filp,
  684. unsigned int cmd, unsigned long arg)
  685. {
  686. return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg);
  687. }
  688. static inline int
  689. nilfs_compat_ioctl_get_cpstat(struct inode *inode, struct file *filp,
  690. unsigned int cmd, unsigned long arg)
  691. {
  692. return nilfs_compat_locked_ioctl(inode, filp, cmd, arg);
  693. }
  694. static inline int
  695. nilfs_compat_ioctl_get_suinfo(struct inode *inode, struct file *filp,
  696. unsigned int cmd, unsigned long arg)
  697. {
  698. return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg);
  699. }
  700. static int
  701. nilfs_compat_ioctl_get_sustat(struct inode *inode, struct file *filp,
  702. unsigned int cmd, unsigned long arg)
  703. {
  704. struct nilfs_sustat __user *usustat;
  705. struct nilfs_sustat32 __user *usustat32;
  706. time_t ctime, nongc_ctime;
  707. int ret;
  708. usustat = compat_alloc_user_space(sizeof(struct nilfs_sustat));
  709. ret = nilfs_compat_locked_ioctl(inode, filp, cmd,
  710. (unsigned long)usustat);
  711. if (ret < 0)
  712. return ret;
  713. usustat32 = compat_ptr(arg);
  714. if (copy_in_user(&usustat32->ss_nsegs, &usustat->ss_nsegs,
  715. sizeof(__u64)) ||
  716. copy_in_user(&usustat32->ss_ncleansegs, &usustat->ss_ncleansegs,
  717. sizeof(__u64)) ||
  718. copy_in_user(&usustat32->ss_ndirtysegs, &usustat->ss_ndirtysegs,
  719. sizeof(__u64)) ||
  720. get_user(ctime, &usustat->ss_ctime) ||
  721. put_user(ctime, &usustat32->ss_ctime) ||
  722. get_user(nongc_ctime, &usustat->ss_nongc_ctime) ||
  723. put_user(nongc_ctime, &usustat32->ss_nongc_ctime))
  724. return -EFAULT;
  725. return 0;
  726. }
  727. static inline int
  728. nilfs_compat_ioctl_get_vinfo(struct inode *inode, struct file *filp,
  729. unsigned int cmd, unsigned long arg)
  730. {
  731. return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg);
  732. }
  733. static inline int
  734. nilfs_compat_ioctl_get_bdescs(struct inode *inode, struct file *filp,
  735. unsigned int cmd, unsigned long arg)
  736. {
  737. return nilfs_compat_ioctl_get_by_argv(inode, filp, cmd, arg);
  738. }
  739. static int
  740. nilfs_compat_ioctl_clean_segments(struct inode *inode, struct file *filp,
  741. unsigned int cmd, unsigned long arg)
  742. {
  743. struct nilfs_argv __user *uargv;
  744. struct nilfs_argv32 __user *uargv32;
  745. int i, ret;
  746. uargv = compat_alloc_user_space(sizeof(struct nilfs_argv) * 5);
  747. uargv32 = compat_ptr(arg);
  748. for (i = 0; i < 5; i++) {
  749. ret = nilfs_compat_ioctl_uargv32_to_uargv(&uargv32[i],
  750. &uargv[i]);
  751. if (ret < 0)
  752. return ret;
  753. }
  754. return nilfs_compat_locked_ioctl(
  755. inode, filp, cmd, (unsigned long)uargv);
  756. }
  757. static int
  758. nilfs_compat_ioctl_timedwait(struct inode *inode, struct file *filp,
  759. unsigned int cmd, unsigned long arg)
  760. {
  761. struct nilfs_wait_cond __user *uwcond;
  762. struct nilfs_wait_cond32 __user *uwcond32;
  763. struct timespec ts;
  764. int cond, flags, ret;
  765. uwcond = compat_alloc_user_space(sizeof(struct nilfs_wait_cond));
  766. uwcond32 = compat_ptr(arg);
  767. if (get_user(cond, &uwcond32->wc_cond) ||
  768. put_user(cond, &uwcond->wc_cond) ||
  769. get_user(flags, &uwcond32->wc_flags) ||
  770. put_user(flags, &uwcond->wc_flags) ||
  771. get_user(ts.tv_sec, &uwcond32->wc_timeout.tv_sec) ||
  772. get_user(ts.tv_nsec, &uwcond32->wc_timeout.tv_nsec) ||
  773. put_user(ts.tv_sec, &uwcond->wc_timeout.tv_sec) ||
  774. put_user(ts.tv_nsec, &uwcond->wc_timeout.tv_nsec))
  775. return -EFAULT;
  776. ret = nilfs_compat_locked_ioctl(inode, filp, cmd,
  777. (unsigned long)uwcond);
  778. if (ret < 0)
  779. return ret;
  780. if (get_user(ts.tv_sec, &uwcond->wc_timeout.tv_sec) ||
  781. get_user(ts.tv_nsec, &uwcond->wc_timeout.tv_nsec) ||
  782. put_user(ts.tv_sec, &uwcond32->wc_timeout.tv_sec) ||
  783. put_user(ts.tv_nsec, &uwcond32->wc_timeout.tv_nsec))
  784. return -EFAULT;
  785. return 0;
  786. }
  787. static int nilfs_compat_ioctl_sync(struct inode *inode, struct file *filp,
  788. unsigned int cmd, unsigned long arg)
  789. {
  790. return nilfs_compat_locked_ioctl(inode, filp, cmd, arg);
  791. }
  792. long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  793. {
  794. struct inode *inode = filp->f_dentry->d_inode;
  795. switch (cmd) {
  796. case NILFS_IOCTL32_CHANGE_CPMODE:
  797. return nilfs_compat_ioctl_change_cpmode(
  798. inode, filp, NILFS_IOCTL_CHANGE_CPMODE, arg);
  799. case NILFS_IOCTL_DELETE_CHECKPOINT:
  800. return nilfs_compat_ioctl_delete_checkpoint(
  801. inode, filp, cmd, arg);
  802. case NILFS_IOCTL32_GET_CPINFO:
  803. return nilfs_compat_ioctl_get_cpinfo(
  804. inode, filp, NILFS_IOCTL_GET_CPINFO, arg);
  805. case NILFS_IOCTL_GET_CPSTAT:
  806. return nilfs_compat_ioctl_get_cpstat(inode, filp, cmd, arg);
  807. case NILFS_IOCTL32_GET_SUINFO:
  808. return nilfs_compat_ioctl_get_suinfo(
  809. inode, filp, NILFS_IOCTL_GET_SUINFO, arg);
  810. case NILFS_IOCTL32_GET_SUSTAT:
  811. return nilfs_compat_ioctl_get_sustat(
  812. inode, filp, NILFS_IOCTL_GET_SUSTAT, arg);
  813. case NILFS_IOCTL32_GET_VINFO:
  814. return nilfs_compat_ioctl_get_vinfo(
  815. inode, filp, NILFS_IOCTL_GET_VINFO, arg);
  816. case NILFS_IOCTL32_GET_BDESCS:
  817. return nilfs_compat_ioctl_get_bdescs(
  818. inode, filp, NILFS_IOCTL_GET_BDESCS, arg);
  819. case NILFS_IOCTL32_CLEAN_SEGMENTS:
  820. return nilfs_compat_ioctl_clean_segments(
  821. inode, filp, NILFS_IOCTL_CLEAN_SEGMENTS, arg);
  822. case NILFS_IOCTL32_TIMEDWAIT:
  823. return nilfs_compat_ioctl_timedwait(
  824. inode, filp, NILFS_IOCTL_TIMEDWAIT, arg);
  825. case NILFS_IOCTL_SYNC:
  826. return nilfs_compat_ioctl_sync(inode, filp, cmd, arg);
  827. default:
  828. return -ENOIOCTLCMD;
  829. }
  830. }
  831. #endif