cpfile.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. /*
  2. * cpfile.c - NILFS checkpoint file.
  3. *
  4. * Copyright (C) 2006-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/kernel.h>
  23. #include <linux/fs.h>
  24. #include <linux/string.h>
  25. #include <linux/buffer_head.h>
  26. #include <linux/errno.h>
  27. #include <linux/nilfs2_fs.h>
  28. #include "mdt.h"
  29. #include "cpfile.h"
  30. static inline unsigned long
  31. nilfs_cpfile_checkpoints_per_block(const struct inode *cpfile)
  32. {
  33. return NILFS_MDT(cpfile)->mi_entries_per_block;
  34. }
  35. /* block number from the beginning of the file */
  36. static unsigned long
  37. nilfs_cpfile_get_blkoff(const struct inode *cpfile, __u64 cno)
  38. {
  39. __u64 tcno;
  40. BUG_ON(cno == 0); /* checkpoint number 0 is invalid */
  41. tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
  42. do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
  43. return (unsigned long)tcno;
  44. }
  45. /* offset in block */
  46. static unsigned long
  47. nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno)
  48. {
  49. __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
  50. return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
  51. }
  52. static unsigned long
  53. nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile,
  54. __u64 curr,
  55. __u64 max)
  56. {
  57. return min_t(__u64,
  58. nilfs_cpfile_checkpoints_per_block(cpfile) -
  59. nilfs_cpfile_get_offset(cpfile, curr),
  60. max - curr);
  61. }
  62. static inline int nilfs_cpfile_is_in_first(const struct inode *cpfile,
  63. __u64 cno)
  64. {
  65. return nilfs_cpfile_get_blkoff(cpfile, cno) == 0;
  66. }
  67. static unsigned int
  68. nilfs_cpfile_block_add_valid_checkpoints(const struct inode *cpfile,
  69. struct buffer_head *bh,
  70. void *kaddr,
  71. unsigned int n)
  72. {
  73. struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
  74. unsigned int count;
  75. count = le32_to_cpu(cp->cp_checkpoints_count) + n;
  76. cp->cp_checkpoints_count = cpu_to_le32(count);
  77. return count;
  78. }
  79. static unsigned int
  80. nilfs_cpfile_block_sub_valid_checkpoints(const struct inode *cpfile,
  81. struct buffer_head *bh,
  82. void *kaddr,
  83. unsigned int n)
  84. {
  85. struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
  86. unsigned int count;
  87. BUG_ON(le32_to_cpu(cp->cp_checkpoints_count) < n);
  88. count = le32_to_cpu(cp->cp_checkpoints_count) - n;
  89. cp->cp_checkpoints_count = cpu_to_le32(count);
  90. return count;
  91. }
  92. static inline struct nilfs_cpfile_header *
  93. nilfs_cpfile_block_get_header(const struct inode *cpfile,
  94. struct buffer_head *bh,
  95. void *kaddr)
  96. {
  97. return kaddr + bh_offset(bh);
  98. }
  99. static struct nilfs_checkpoint *
  100. nilfs_cpfile_block_get_checkpoint(const struct inode *cpfile, __u64 cno,
  101. struct buffer_head *bh,
  102. void *kaddr)
  103. {
  104. return kaddr + bh_offset(bh) + nilfs_cpfile_get_offset(cpfile, cno) *
  105. NILFS_MDT(cpfile)->mi_entry_size;
  106. }
  107. static void nilfs_cpfile_block_init(struct inode *cpfile,
  108. struct buffer_head *bh,
  109. void *kaddr)
  110. {
  111. struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
  112. size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
  113. int n = nilfs_cpfile_checkpoints_per_block(cpfile);
  114. while (n-- > 0) {
  115. nilfs_checkpoint_set_invalid(cp);
  116. cp = (void *)cp + cpsz;
  117. }
  118. }
  119. static inline int nilfs_cpfile_get_header_block(struct inode *cpfile,
  120. struct buffer_head **bhp)
  121. {
  122. return nilfs_mdt_get_block(cpfile, 0, 0, NULL, bhp);
  123. }
  124. static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile,
  125. __u64 cno,
  126. int create,
  127. struct buffer_head **bhp)
  128. {
  129. return nilfs_mdt_get_block(cpfile,
  130. nilfs_cpfile_get_blkoff(cpfile, cno),
  131. create, nilfs_cpfile_block_init, bhp);
  132. }
  133. static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile,
  134. __u64 cno)
  135. {
  136. return nilfs_mdt_delete_block(cpfile,
  137. nilfs_cpfile_get_blkoff(cpfile, cno));
  138. }
  139. /**
  140. * nilfs_cpfile_get_checkpoint - get a checkpoint
  141. * @cpfile: inode of checkpoint file
  142. * @cno: checkpoint number
  143. * @create: create flag
  144. * @cpp: pointer to a checkpoint
  145. * @bhp: pointer to a buffer head
  146. *
  147. * Description: nilfs_cpfile_get_checkpoint() acquires the checkpoint
  148. * specified by @cno. A new checkpoint will be created if @cno is the current
  149. * checkpoint number and @create is nonzero.
  150. *
  151. * Return Value: On success, 0 is returned, and the checkpoint and the
  152. * buffer head of the buffer on which the checkpoint is located are stored in
  153. * the place pointed by @cpp and @bhp, respectively. On error, one of the
  154. * following negative error codes is returned.
  155. *
  156. * %-EIO - I/O error.
  157. *
  158. * %-ENOMEM - Insufficient amount of memory available.
  159. *
  160. * %-ENOENT - No such checkpoint.
  161. */
  162. int nilfs_cpfile_get_checkpoint(struct inode *cpfile,
  163. __u64 cno,
  164. int create,
  165. struct nilfs_checkpoint **cpp,
  166. struct buffer_head **bhp)
  167. {
  168. struct buffer_head *header_bh, *cp_bh;
  169. struct nilfs_cpfile_header *header;
  170. struct nilfs_checkpoint *cp;
  171. void *kaddr;
  172. int ret;
  173. BUG_ON(cno < 1 || cno > nilfs_mdt_cno(cpfile) ||
  174. (cno < nilfs_mdt_cno(cpfile) && create));
  175. down_write(&NILFS_MDT(cpfile)->mi_sem);
  176. ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
  177. if (ret < 0)
  178. goto out_sem;
  179. ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, create, &cp_bh);
  180. if (ret < 0)
  181. goto out_header;
  182. kaddr = kmap(cp_bh->b_page);
  183. cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
  184. if (nilfs_checkpoint_invalid(cp)) {
  185. if (!create) {
  186. kunmap(cp_bh->b_page);
  187. brelse(cp_bh);
  188. ret = -ENOENT;
  189. goto out_header;
  190. }
  191. /* a newly-created checkpoint */
  192. nilfs_checkpoint_clear_invalid(cp);
  193. if (!nilfs_cpfile_is_in_first(cpfile, cno))
  194. nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,
  195. kaddr, 1);
  196. nilfs_mdt_mark_buffer_dirty(cp_bh);
  197. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  198. header = nilfs_cpfile_block_get_header(cpfile, header_bh,
  199. kaddr);
  200. le64_add_cpu(&header->ch_ncheckpoints, 1);
  201. kunmap_atomic(kaddr, KM_USER0);
  202. nilfs_mdt_mark_buffer_dirty(header_bh);
  203. nilfs_mdt_mark_dirty(cpfile);
  204. }
  205. if (cpp != NULL)
  206. *cpp = cp;
  207. *bhp = cp_bh;
  208. out_header:
  209. brelse(header_bh);
  210. out_sem:
  211. up_write(&NILFS_MDT(cpfile)->mi_sem);
  212. return ret;
  213. }
  214. /**
  215. * nilfs_cpfile_put_checkpoint - put a checkpoint
  216. * @cpfile: inode of checkpoint file
  217. * @cno: checkpoint number
  218. * @bh: buffer head
  219. *
  220. * Description: nilfs_cpfile_put_checkpoint() releases the checkpoint
  221. * specified by @cno. @bh must be the buffer head which has been returned by
  222. * a previous call to nilfs_cpfile_get_checkpoint() with @cno.
  223. */
  224. void nilfs_cpfile_put_checkpoint(struct inode *cpfile, __u64 cno,
  225. struct buffer_head *bh)
  226. {
  227. kunmap(bh->b_page);
  228. brelse(bh);
  229. }
  230. /**
  231. * nilfs_cpfile_delete_checkpoints - delete checkpoints
  232. * @cpfile: inode of checkpoint file
  233. * @start: start checkpoint number
  234. * @end: end checkpoint numer
  235. *
  236. * Description: nilfs_cpfile_delete_checkpoints() deletes the checkpoints in
  237. * the period from @start to @end, excluding @end itself. The checkpoints
  238. * which have been already deleted are ignored.
  239. *
  240. * Return Value: On success, 0 is returned. On error, one of the following
  241. * negative error codes is returned.
  242. *
  243. * %-EIO - I/O error.
  244. *
  245. * %-ENOMEM - Insufficient amount of memory available.
  246. *
  247. * %-EINVAL - invalid checkpoints.
  248. */
  249. int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
  250. __u64 start,
  251. __u64 end)
  252. {
  253. struct buffer_head *header_bh, *cp_bh;
  254. struct nilfs_cpfile_header *header;
  255. struct nilfs_checkpoint *cp;
  256. size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
  257. __u64 cno;
  258. void *kaddr;
  259. unsigned long tnicps;
  260. int ret, ncps, nicps, count, i;
  261. if ((start == 0) || (start > end)) {
  262. printk(KERN_CRIT "%s: start = %llu, end = %llu\n",
  263. __func__,
  264. (unsigned long long)start,
  265. (unsigned long long)end);
  266. BUG();
  267. }
  268. /* cannot delete the latest checkpoint */
  269. if (start == nilfs_mdt_cno(cpfile) - 1)
  270. return -EPERM;
  271. down_write(&NILFS_MDT(cpfile)->mi_sem);
  272. ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
  273. if (ret < 0)
  274. goto out_sem;
  275. tnicps = 0;
  276. for (cno = start; cno < end; cno += ncps) {
  277. ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end);
  278. ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
  279. if (ret < 0) {
  280. if (ret != -ENOENT)
  281. goto out_sem;
  282. /* skip hole */
  283. ret = 0;
  284. continue;
  285. }
  286. kaddr = kmap_atomic(cp_bh->b_page, KM_USER0);
  287. cp = nilfs_cpfile_block_get_checkpoint(
  288. cpfile, cno, cp_bh, kaddr);
  289. nicps = 0;
  290. for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) {
  291. BUG_ON(nilfs_checkpoint_snapshot(cp));
  292. if (!nilfs_checkpoint_invalid(cp)) {
  293. nilfs_checkpoint_set_invalid(cp);
  294. nicps++;
  295. }
  296. }
  297. if (nicps > 0) {
  298. tnicps += nicps;
  299. nilfs_mdt_mark_buffer_dirty(cp_bh);
  300. nilfs_mdt_mark_dirty(cpfile);
  301. if (!nilfs_cpfile_is_in_first(cpfile, cno) &&
  302. (count = nilfs_cpfile_block_sub_valid_checkpoints(
  303. cpfile, cp_bh, kaddr, nicps)) == 0) {
  304. /* make hole */
  305. kunmap_atomic(kaddr, KM_USER0);
  306. brelse(cp_bh);
  307. ret = nilfs_cpfile_delete_checkpoint_block(
  308. cpfile, cno);
  309. if (ret == 0)
  310. continue;
  311. printk(KERN_ERR "%s: cannot delete block\n",
  312. __func__);
  313. goto out_sem;
  314. }
  315. }
  316. kunmap_atomic(kaddr, KM_USER0);
  317. brelse(cp_bh);
  318. }
  319. if (tnicps > 0) {
  320. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  321. header = nilfs_cpfile_block_get_header(cpfile, header_bh,
  322. kaddr);
  323. le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps);
  324. nilfs_mdt_mark_buffer_dirty(header_bh);
  325. nilfs_mdt_mark_dirty(cpfile);
  326. kunmap_atomic(kaddr, KM_USER0);
  327. }
  328. brelse(header_bh);
  329. out_sem:
  330. up_write(&NILFS_MDT(cpfile)->mi_sem);
  331. return ret;
  332. }
  333. static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,
  334. struct nilfs_checkpoint *cp,
  335. struct nilfs_cpinfo *ci)
  336. {
  337. ci->ci_flags = le32_to_cpu(cp->cp_flags);
  338. ci->ci_cno = le64_to_cpu(cp->cp_cno);
  339. ci->ci_create = le64_to_cpu(cp->cp_create);
  340. ci->ci_nblk_inc = le64_to_cpu(cp->cp_nblk_inc);
  341. ci->ci_inodes_count = le64_to_cpu(cp->cp_inodes_count);
  342. ci->ci_blocks_count = le64_to_cpu(cp->cp_blocks_count);
  343. ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
  344. }
  345. static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 cno,
  346. struct nilfs_cpinfo *ci, size_t nci)
  347. {
  348. struct nilfs_checkpoint *cp;
  349. struct buffer_head *bh;
  350. size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
  351. __u64 cur_cno = nilfs_mdt_cno(cpfile);
  352. void *kaddr;
  353. int n, ret;
  354. int ncps, i;
  355. down_read(&NILFS_MDT(cpfile)->mi_sem);
  356. for (n = 0; cno < cur_cno && n < nci; cno += ncps) {
  357. ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno);
  358. ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);
  359. if (ret < 0) {
  360. if (ret != -ENOENT)
  361. goto out;
  362. continue; /* skip hole */
  363. }
  364. kaddr = kmap_atomic(bh->b_page, KM_USER0);
  365. cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
  366. for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) {
  367. if (!nilfs_checkpoint_invalid(cp))
  368. nilfs_cpfile_checkpoint_to_cpinfo(
  369. cpfile, cp, &ci[n++]);
  370. }
  371. kunmap_atomic(kaddr, KM_USER0);
  372. brelse(bh);
  373. }
  374. ret = n;
  375. out:
  376. up_read(&NILFS_MDT(cpfile)->mi_sem);
  377. return ret;
  378. }
  379. static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
  380. struct nilfs_cpinfo *ci, size_t nci)
  381. {
  382. struct buffer_head *bh;
  383. struct nilfs_cpfile_header *header;
  384. struct nilfs_checkpoint *cp;
  385. __u64 curr = *cnop, next;
  386. unsigned long curr_blkoff, next_blkoff;
  387. void *kaddr;
  388. int n, ret;
  389. down_read(&NILFS_MDT(cpfile)->mi_sem);
  390. if (curr == 0) {
  391. ret = nilfs_cpfile_get_header_block(cpfile, &bh);
  392. if (ret < 0)
  393. goto out;
  394. kaddr = kmap_atomic(bh->b_page, KM_USER0);
  395. header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
  396. curr = le64_to_cpu(header->ch_snapshot_list.ssl_next);
  397. kunmap_atomic(kaddr, KM_USER0);
  398. brelse(bh);
  399. if (curr == 0) {
  400. ret = 0;
  401. goto out;
  402. }
  403. } else if (unlikely(curr == ~(__u64)0)) {
  404. ret = 0;
  405. goto out;
  406. }
  407. curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr);
  408. ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh);
  409. if (ret < 0)
  410. goto out;
  411. kaddr = kmap_atomic(bh->b_page, KM_USER0);
  412. for (n = 0; n < nci; n++) {
  413. cp = nilfs_cpfile_block_get_checkpoint(
  414. cpfile, curr, bh, kaddr);
  415. nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n]);
  416. next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
  417. if (next == 0) {
  418. curr = ~(__u64)0; /* Terminator */
  419. n++;
  420. break;
  421. }
  422. next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next);
  423. if (curr_blkoff != next_blkoff) {
  424. kunmap_atomic(kaddr, KM_USER0);
  425. brelse(bh);
  426. ret = nilfs_cpfile_get_checkpoint_block(cpfile, next,
  427. 0, &bh);
  428. if (ret < 0)
  429. goto out;
  430. kaddr = kmap_atomic(bh->b_page, KM_USER0);
  431. }
  432. curr = next;
  433. curr_blkoff = next_blkoff;
  434. }
  435. kunmap_atomic(kaddr, KM_USER0);
  436. brelse(bh);
  437. *cnop = curr;
  438. ret = n;
  439. out:
  440. up_read(&NILFS_MDT(cpfile)->mi_sem);
  441. return ret;
  442. }
  443. /**
  444. * nilfs_cpfile_get_cpinfo -
  445. * @cpfile:
  446. * @cno:
  447. * @ci:
  448. * @nci:
  449. */
  450. ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
  451. struct nilfs_cpinfo *ci, size_t nci)
  452. {
  453. switch (mode) {
  454. case NILFS_CHECKPOINT:
  455. return nilfs_cpfile_do_get_cpinfo(cpfile, *cnop, ci, nci);
  456. case NILFS_SNAPSHOT:
  457. return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci);
  458. default:
  459. return -EINVAL;
  460. }
  461. }
  462. /**
  463. * nilfs_cpfile_delete_checkpoint -
  464. * @cpfile:
  465. * @cno:
  466. */
  467. int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)
  468. {
  469. struct nilfs_cpinfo ci;
  470. ssize_t nci;
  471. int ret;
  472. /* checkpoint number 0 is invalid */
  473. if (cno == 0)
  474. return -ENOENT;
  475. nci = nilfs_cpfile_do_get_cpinfo(cpfile, cno, &ci, 1);
  476. if (nci < 0)
  477. return nci;
  478. else if (nci == 0 || ci.ci_cno != cno)
  479. return -ENOENT;
  480. /* cannot delete the latest checkpoint nor snapshots */
  481. ret = nilfs_cpinfo_snapshot(&ci);
  482. if (ret < 0)
  483. return ret;
  484. else if (ret > 0 || cno == nilfs_mdt_cno(cpfile) - 1)
  485. return -EPERM;
  486. return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1);
  487. }
  488. static struct nilfs_snapshot_list *
  489. nilfs_cpfile_block_get_snapshot_list(const struct inode *cpfile,
  490. __u64 cno,
  491. struct buffer_head *bh,
  492. void *kaddr)
  493. {
  494. struct nilfs_cpfile_header *header;
  495. struct nilfs_checkpoint *cp;
  496. struct nilfs_snapshot_list *list;
  497. if (cno != 0) {
  498. cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
  499. list = &cp->cp_snapshot_list;
  500. } else {
  501. header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
  502. list = &header->ch_snapshot_list;
  503. }
  504. return list;
  505. }
  506. static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
  507. {
  508. struct buffer_head *header_bh, *curr_bh, *prev_bh, *cp_bh;
  509. struct nilfs_cpfile_header *header;
  510. struct nilfs_checkpoint *cp;
  511. struct nilfs_snapshot_list *list;
  512. __u64 curr, prev;
  513. unsigned long curr_blkoff, prev_blkoff;
  514. void *kaddr;
  515. int ret;
  516. down_write(&NILFS_MDT(cpfile)->mi_sem);
  517. ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
  518. if (ret < 0)
  519. goto out_sem;
  520. kaddr = kmap_atomic(cp_bh->b_page, KM_USER0);
  521. cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
  522. if (nilfs_checkpoint_invalid(cp)) {
  523. ret = -ENOENT;
  524. kunmap_atomic(kaddr, KM_USER0);
  525. goto out_cp;
  526. }
  527. if (nilfs_checkpoint_snapshot(cp)) {
  528. ret = 0;
  529. kunmap_atomic(kaddr, KM_USER0);
  530. goto out_cp;
  531. }
  532. kunmap_atomic(kaddr, KM_USER0);
  533. ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
  534. if (ret < 0)
  535. goto out_cp;
  536. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  537. header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
  538. list = &header->ch_snapshot_list;
  539. curr_bh = header_bh;
  540. get_bh(curr_bh);
  541. curr = 0;
  542. curr_blkoff = 0;
  543. prev = le64_to_cpu(list->ssl_prev);
  544. while (prev > cno) {
  545. prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev);
  546. curr = prev;
  547. if (curr_blkoff != prev_blkoff) {
  548. kunmap_atomic(kaddr, KM_USER0);
  549. brelse(curr_bh);
  550. ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr,
  551. 0, &curr_bh);
  552. if (ret < 0)
  553. goto out_header;
  554. kaddr = kmap_atomic(curr_bh->b_page, KM_USER0);
  555. }
  556. curr_blkoff = prev_blkoff;
  557. cp = nilfs_cpfile_block_get_checkpoint(
  558. cpfile, curr, curr_bh, kaddr);
  559. list = &cp->cp_snapshot_list;
  560. prev = le64_to_cpu(list->ssl_prev);
  561. }
  562. kunmap_atomic(kaddr, KM_USER0);
  563. if (prev != 0) {
  564. ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
  565. &prev_bh);
  566. if (ret < 0)
  567. goto out_curr;
  568. } else {
  569. prev_bh = header_bh;
  570. get_bh(prev_bh);
  571. }
  572. kaddr = kmap_atomic(curr_bh->b_page, KM_USER0);
  573. list = nilfs_cpfile_block_get_snapshot_list(
  574. cpfile, curr, curr_bh, kaddr);
  575. list->ssl_prev = cpu_to_le64(cno);
  576. kunmap_atomic(kaddr, KM_USER0);
  577. kaddr = kmap_atomic(cp_bh->b_page, KM_USER0);
  578. cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
  579. cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr);
  580. cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev);
  581. nilfs_checkpoint_set_snapshot(cp);
  582. kunmap_atomic(kaddr, KM_USER0);
  583. kaddr = kmap_atomic(prev_bh->b_page, KM_USER0);
  584. list = nilfs_cpfile_block_get_snapshot_list(
  585. cpfile, prev, prev_bh, kaddr);
  586. list->ssl_next = cpu_to_le64(cno);
  587. kunmap_atomic(kaddr, KM_USER0);
  588. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  589. header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
  590. le64_add_cpu(&header->ch_nsnapshots, 1);
  591. kunmap_atomic(kaddr, KM_USER0);
  592. nilfs_mdt_mark_buffer_dirty(prev_bh);
  593. nilfs_mdt_mark_buffer_dirty(curr_bh);
  594. nilfs_mdt_mark_buffer_dirty(cp_bh);
  595. nilfs_mdt_mark_buffer_dirty(header_bh);
  596. nilfs_mdt_mark_dirty(cpfile);
  597. brelse(prev_bh);
  598. out_curr:
  599. brelse(curr_bh);
  600. out_header:
  601. brelse(header_bh);
  602. out_cp:
  603. brelse(cp_bh);
  604. out_sem:
  605. up_write(&NILFS_MDT(cpfile)->mi_sem);
  606. return ret;
  607. }
  608. static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
  609. {
  610. struct buffer_head *header_bh, *next_bh, *prev_bh, *cp_bh;
  611. struct nilfs_cpfile_header *header;
  612. struct nilfs_checkpoint *cp;
  613. struct nilfs_snapshot_list *list;
  614. __u64 next, prev;
  615. void *kaddr;
  616. int ret;
  617. down_write(&NILFS_MDT(cpfile)->mi_sem);
  618. ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
  619. if (ret < 0)
  620. goto out_sem;
  621. kaddr = kmap_atomic(cp_bh->b_page, KM_USER0);
  622. cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
  623. if (nilfs_checkpoint_invalid(cp)) {
  624. ret = -ENOENT;
  625. kunmap_atomic(kaddr, KM_USER0);
  626. goto out_cp;
  627. }
  628. if (!nilfs_checkpoint_snapshot(cp)) {
  629. ret = 0;
  630. kunmap_atomic(kaddr, KM_USER0);
  631. goto out_cp;
  632. }
  633. list = &cp->cp_snapshot_list;
  634. next = le64_to_cpu(list->ssl_next);
  635. prev = le64_to_cpu(list->ssl_prev);
  636. kunmap_atomic(kaddr, KM_USER0);
  637. ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
  638. if (ret < 0)
  639. goto out_cp;
  640. if (next != 0) {
  641. ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0,
  642. &next_bh);
  643. if (ret < 0)
  644. goto out_header;
  645. } else {
  646. next_bh = header_bh;
  647. get_bh(next_bh);
  648. }
  649. if (prev != 0) {
  650. ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
  651. &prev_bh);
  652. if (ret < 0)
  653. goto out_next;
  654. } else {
  655. prev_bh = header_bh;
  656. get_bh(prev_bh);
  657. }
  658. kaddr = kmap_atomic(next_bh->b_page, KM_USER0);
  659. list = nilfs_cpfile_block_get_snapshot_list(
  660. cpfile, next, next_bh, kaddr);
  661. list->ssl_prev = cpu_to_le64(prev);
  662. kunmap_atomic(kaddr, KM_USER0);
  663. kaddr = kmap_atomic(prev_bh->b_page, KM_USER0);
  664. list = nilfs_cpfile_block_get_snapshot_list(
  665. cpfile, prev, prev_bh, kaddr);
  666. list->ssl_next = cpu_to_le64(next);
  667. kunmap_atomic(kaddr, KM_USER0);
  668. kaddr = kmap_atomic(cp_bh->b_page, KM_USER0);
  669. cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
  670. cp->cp_snapshot_list.ssl_next = cpu_to_le64(0);
  671. cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0);
  672. nilfs_checkpoint_clear_snapshot(cp);
  673. kunmap_atomic(kaddr, KM_USER0);
  674. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  675. header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
  676. le64_add_cpu(&header->ch_nsnapshots, -1);
  677. kunmap_atomic(kaddr, KM_USER0);
  678. nilfs_mdt_mark_buffer_dirty(next_bh);
  679. nilfs_mdt_mark_buffer_dirty(prev_bh);
  680. nilfs_mdt_mark_buffer_dirty(cp_bh);
  681. nilfs_mdt_mark_buffer_dirty(header_bh);
  682. nilfs_mdt_mark_dirty(cpfile);
  683. brelse(prev_bh);
  684. out_next:
  685. brelse(next_bh);
  686. out_header:
  687. brelse(header_bh);
  688. out_cp:
  689. brelse(cp_bh);
  690. out_sem:
  691. up_write(&NILFS_MDT(cpfile)->mi_sem);
  692. return ret;
  693. }
  694. /**
  695. * nilfs_cpfile_is_snapshot -
  696. * @cpfile: inode of checkpoint file
  697. * @cno: checkpoint number
  698. *
  699. * Description:
  700. *
  701. * Return Value: On success, 1 is returned if the checkpoint specified by
  702. * @cno is a snapshot, or 0 if not. On error, one of the following negative
  703. * error codes is returned.
  704. *
  705. * %-EIO - I/O error.
  706. *
  707. * %-ENOMEM - Insufficient amount of memory available.
  708. *
  709. * %-ENOENT - No such checkpoint.
  710. */
  711. int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno)
  712. {
  713. struct buffer_head *bh;
  714. struct nilfs_checkpoint *cp;
  715. void *kaddr;
  716. int ret;
  717. down_read(&NILFS_MDT(cpfile)->mi_sem);
  718. ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);
  719. if (ret < 0)
  720. goto out;
  721. kaddr = kmap_atomic(bh->b_page, KM_USER0);
  722. cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
  723. ret = nilfs_checkpoint_snapshot(cp);
  724. kunmap_atomic(kaddr, KM_USER0);
  725. brelse(bh);
  726. out:
  727. up_read(&NILFS_MDT(cpfile)->mi_sem);
  728. return ret;
  729. }
  730. /**
  731. * nilfs_cpfile_change_cpmode - change checkpoint mode
  732. * @cpfile: inode of checkpoint file
  733. * @cno: checkpoint number
  734. * @status: mode of checkpoint
  735. *
  736. * Description: nilfs_change_cpmode() changes the mode of the checkpoint
  737. * specified by @cno. The mode @mode is NILFS_CHECKPOINT or NILFS_SNAPSHOT.
  738. *
  739. * Return Value: On success, 0 is returned. On error, one of the following
  740. * negative error codes is returned.
  741. *
  742. * %-EIO - I/O error.
  743. *
  744. * %-ENOMEM - Insufficient amount of memory available.
  745. *
  746. * %-ENOENT - No such checkpoint.
  747. */
  748. int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
  749. {
  750. struct the_nilfs *nilfs;
  751. int ret;
  752. nilfs = NILFS_MDT(cpfile)->mi_nilfs;
  753. switch (mode) {
  754. case NILFS_CHECKPOINT:
  755. /*
  756. * Check for protecting existing snapshot mounts:
  757. * bd_mount_sem is used to make this operation atomic and
  758. * exclusive with a new mount job. Though it doesn't cover
  759. * umount, it's enough for the purpose.
  760. */
  761. down(&nilfs->ns_bdev->bd_mount_sem);
  762. if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) {
  763. /* Current implementation does not have to protect
  764. plain read-only mounts since they are exclusive
  765. with a read/write mount and are protected from the
  766. cleaner. */
  767. ret = -EBUSY;
  768. } else
  769. ret = nilfs_cpfile_clear_snapshot(cpfile, cno);
  770. up(&nilfs->ns_bdev->bd_mount_sem);
  771. return ret;
  772. case NILFS_SNAPSHOT:
  773. return nilfs_cpfile_set_snapshot(cpfile, cno);
  774. default:
  775. return -EINVAL;
  776. }
  777. }
  778. /**
  779. * nilfs_cpfile_get_stat - get checkpoint statistics
  780. * @cpfile: inode of checkpoint file
  781. * @stat: pointer to a structure of checkpoint statistics
  782. *
  783. * Description: nilfs_cpfile_get_stat() returns information about checkpoints.
  784. *
  785. * Return Value: On success, 0 is returned, and checkpoints information is
  786. * stored in the place pointed by @stat. On error, one of the following
  787. * negative error codes is returned.
  788. *
  789. * %-EIO - I/O error.
  790. *
  791. * %-ENOMEM - Insufficient amount of memory available.
  792. */
  793. int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat)
  794. {
  795. struct buffer_head *bh;
  796. struct nilfs_cpfile_header *header;
  797. void *kaddr;
  798. int ret;
  799. down_read(&NILFS_MDT(cpfile)->mi_sem);
  800. ret = nilfs_cpfile_get_header_block(cpfile, &bh);
  801. if (ret < 0)
  802. goto out_sem;
  803. kaddr = kmap_atomic(bh->b_page, KM_USER0);
  804. header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
  805. cpstat->cs_cno = nilfs_mdt_cno(cpfile);
  806. cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints);
  807. cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots);
  808. kunmap_atomic(kaddr, KM_USER0);
  809. brelse(bh);
  810. out_sem:
  811. up_read(&NILFS_MDT(cpfile)->mi_sem);
  812. return ret;
  813. }