ioctl.c 25 KB

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