sufile.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. /*
  2. * sufile.c - NILFS segment usage 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 "sufile.h"
  30. static inline unsigned long
  31. nilfs_sufile_segment_usages_per_block(const struct inode *sufile)
  32. {
  33. return NILFS_MDT(sufile)->mi_entries_per_block;
  34. }
  35. static unsigned long
  36. nilfs_sufile_get_blkoff(const struct inode *sufile, __u64 segnum)
  37. {
  38. __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset;
  39. do_div(t, nilfs_sufile_segment_usages_per_block(sufile));
  40. return (unsigned long)t;
  41. }
  42. static unsigned long
  43. nilfs_sufile_get_offset(const struct inode *sufile, __u64 segnum)
  44. {
  45. __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset;
  46. return do_div(t, nilfs_sufile_segment_usages_per_block(sufile));
  47. }
  48. static unsigned long
  49. nilfs_sufile_segment_usages_in_block(const struct inode *sufile, __u64 curr,
  50. __u64 max)
  51. {
  52. return min_t(unsigned long,
  53. nilfs_sufile_segment_usages_per_block(sufile) -
  54. nilfs_sufile_get_offset(sufile, curr),
  55. max - curr + 1);
  56. }
  57. static inline struct nilfs_sufile_header *
  58. nilfs_sufile_block_get_header(const struct inode *sufile,
  59. struct buffer_head *bh,
  60. void *kaddr)
  61. {
  62. return kaddr + bh_offset(bh);
  63. }
  64. static struct nilfs_segment_usage *
  65. nilfs_sufile_block_get_segment_usage(const struct inode *sufile, __u64 segnum,
  66. struct buffer_head *bh, void *kaddr)
  67. {
  68. return kaddr + bh_offset(bh) +
  69. nilfs_sufile_get_offset(sufile, segnum) *
  70. NILFS_MDT(sufile)->mi_entry_size;
  71. }
  72. static inline int nilfs_sufile_get_header_block(struct inode *sufile,
  73. struct buffer_head **bhp)
  74. {
  75. return nilfs_mdt_get_block(sufile, 0, 0, NULL, bhp);
  76. }
  77. static inline int
  78. nilfs_sufile_get_segment_usage_block(struct inode *sufile, __u64 segnum,
  79. int create, struct buffer_head **bhp)
  80. {
  81. return nilfs_mdt_get_block(sufile,
  82. nilfs_sufile_get_blkoff(sufile, segnum),
  83. create, NULL, bhp);
  84. }
  85. /**
  86. * nilfs_sufile_alloc - allocate a segment
  87. * @sufile: inode of segment usage file
  88. * @segnump: pointer to segment number
  89. *
  90. * Description: nilfs_sufile_alloc() allocates a clean segment.
  91. *
  92. * Return Value: On success, 0 is returned and the segment number of the
  93. * allocated segment is stored in the place pointed by @segnump. On error, one
  94. * of the following negative error codes is returned.
  95. *
  96. * %-EIO - I/O error.
  97. *
  98. * %-ENOMEM - Insufficient amount of memory available.
  99. *
  100. * %-ENOSPC - No clean segment left.
  101. */
  102. int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump)
  103. {
  104. struct buffer_head *header_bh, *su_bh;
  105. struct the_nilfs *nilfs;
  106. struct nilfs_sufile_header *header;
  107. struct nilfs_segment_usage *su;
  108. size_t susz = NILFS_MDT(sufile)->mi_entry_size;
  109. __u64 segnum, maxsegnum, last_alloc;
  110. void *kaddr;
  111. unsigned long nsegments, ncleansegs, nsus;
  112. int ret, i, j;
  113. down_write(&NILFS_MDT(sufile)->mi_sem);
  114. nilfs = NILFS_MDT(sufile)->mi_nilfs;
  115. ret = nilfs_sufile_get_header_block(sufile, &header_bh);
  116. if (ret < 0)
  117. goto out_sem;
  118. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  119. header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr);
  120. ncleansegs = le64_to_cpu(header->sh_ncleansegs);
  121. last_alloc = le64_to_cpu(header->sh_last_alloc);
  122. kunmap_atomic(kaddr, KM_USER0);
  123. nsegments = nilfs_sufile_get_nsegments(sufile);
  124. segnum = last_alloc + 1;
  125. maxsegnum = nsegments - 1;
  126. for (i = 0; i < nsegments; i += nsus) {
  127. if (segnum >= nsegments) {
  128. /* wrap around */
  129. segnum = 0;
  130. maxsegnum = last_alloc;
  131. }
  132. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1,
  133. &su_bh);
  134. if (ret < 0)
  135. goto out_header;
  136. kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
  137. su = nilfs_sufile_block_get_segment_usage(
  138. sufile, segnum, su_bh, kaddr);
  139. nsus = nilfs_sufile_segment_usages_in_block(
  140. sufile, segnum, maxsegnum);
  141. for (j = 0; j < nsus; j++, su = (void *)su + susz, segnum++) {
  142. if (!nilfs_segment_usage_clean(su))
  143. continue;
  144. /* found a clean segment */
  145. nilfs_segment_usage_set_dirty(su);
  146. kunmap_atomic(kaddr, KM_USER0);
  147. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  148. header = nilfs_sufile_block_get_header(
  149. sufile, header_bh, kaddr);
  150. le64_add_cpu(&header->sh_ncleansegs, -1);
  151. le64_add_cpu(&header->sh_ndirtysegs, 1);
  152. header->sh_last_alloc = cpu_to_le64(segnum);
  153. kunmap_atomic(kaddr, KM_USER0);
  154. nilfs_mdt_mark_buffer_dirty(header_bh);
  155. nilfs_mdt_mark_buffer_dirty(su_bh);
  156. nilfs_mdt_mark_dirty(sufile);
  157. brelse(su_bh);
  158. *segnump = segnum;
  159. goto out_header;
  160. }
  161. kunmap_atomic(kaddr, KM_USER0);
  162. brelse(su_bh);
  163. }
  164. /* no segments left */
  165. ret = -ENOSPC;
  166. out_header:
  167. brelse(header_bh);
  168. out_sem:
  169. up_write(&NILFS_MDT(sufile)->mi_sem);
  170. return ret;
  171. }
  172. /**
  173. * nilfs_sufile_cancel_free -
  174. * @sufile: inode of segment usage file
  175. * @segnum: segment number
  176. *
  177. * Description:
  178. *
  179. * Return Value: On success, 0 is returned. On error, one of the following
  180. * negative error codes is returned.
  181. *
  182. * %-EIO - I/O error.
  183. *
  184. * %-ENOMEM - Insufficient amount of memory available.
  185. */
  186. int nilfs_sufile_cancel_free(struct inode *sufile, __u64 segnum)
  187. {
  188. struct buffer_head *header_bh, *su_bh;
  189. struct the_nilfs *nilfs;
  190. struct nilfs_sufile_header *header;
  191. struct nilfs_segment_usage *su;
  192. void *kaddr;
  193. int ret;
  194. down_write(&NILFS_MDT(sufile)->mi_sem);
  195. nilfs = NILFS_MDT(sufile)->mi_nilfs;
  196. ret = nilfs_sufile_get_header_block(sufile, &header_bh);
  197. if (ret < 0)
  198. goto out_sem;
  199. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &su_bh);
  200. if (ret < 0)
  201. goto out_header;
  202. kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
  203. su = nilfs_sufile_block_get_segment_usage(
  204. sufile, segnum, su_bh, kaddr);
  205. if (unlikely(!nilfs_segment_usage_clean(su))) {
  206. printk(KERN_WARNING "%s: segment %llu must be clean\n",
  207. __func__, (unsigned long long)segnum);
  208. kunmap_atomic(kaddr, KM_USER0);
  209. goto out_su_bh;
  210. }
  211. nilfs_segment_usage_set_dirty(su);
  212. kunmap_atomic(kaddr, KM_USER0);
  213. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  214. header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr);
  215. le64_add_cpu(&header->sh_ncleansegs, -1);
  216. le64_add_cpu(&header->sh_ndirtysegs, 1);
  217. kunmap_atomic(kaddr, KM_USER0);
  218. nilfs_mdt_mark_buffer_dirty(header_bh);
  219. nilfs_mdt_mark_buffer_dirty(su_bh);
  220. nilfs_mdt_mark_dirty(sufile);
  221. out_su_bh:
  222. brelse(su_bh);
  223. out_header:
  224. brelse(header_bh);
  225. out_sem:
  226. up_write(&NILFS_MDT(sufile)->mi_sem);
  227. return ret;
  228. }
  229. /**
  230. * nilfs_sufile_freev - free segments
  231. * @sufile: inode of segment usage file
  232. * @segnum: array of segment numbers
  233. * @nsegs: number of segments
  234. *
  235. * Description: nilfs_sufile_freev() frees segments specified by @segnum and
  236. * @nsegs, which must have been returned by a previous call to
  237. * nilfs_sufile_alloc().
  238. *
  239. * Return Value: On success, 0 is returned. On error, one of the following
  240. * negative error codes is returned.
  241. *
  242. * %-EIO - I/O error.
  243. *
  244. * %-ENOMEM - Insufficient amount of memory available.
  245. */
  246. #define NILFS_SUFILE_FREEV_PREALLOC 16
  247. int nilfs_sufile_freev(struct inode *sufile, __u64 *segnum, size_t nsegs)
  248. {
  249. struct buffer_head *header_bh, **su_bh,
  250. *su_bh_prealloc[NILFS_SUFILE_FREEV_PREALLOC];
  251. struct the_nilfs *nilfs;
  252. struct nilfs_sufile_header *header;
  253. struct nilfs_segment_usage *su;
  254. void *kaddr;
  255. int ret, i;
  256. down_write(&NILFS_MDT(sufile)->mi_sem);
  257. nilfs = NILFS_MDT(sufile)->mi_nilfs;
  258. /* prepare resources */
  259. if (nsegs <= NILFS_SUFILE_FREEV_PREALLOC)
  260. su_bh = su_bh_prealloc;
  261. else {
  262. su_bh = kmalloc(sizeof(*su_bh) * nsegs, GFP_NOFS);
  263. if (su_bh == NULL) {
  264. ret = -ENOMEM;
  265. goto out_sem;
  266. }
  267. }
  268. ret = nilfs_sufile_get_header_block(sufile, &header_bh);
  269. if (ret < 0)
  270. goto out_su_bh;
  271. for (i = 0; i < nsegs; i++) {
  272. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum[i],
  273. 0, &su_bh[i]);
  274. if (ret < 0)
  275. goto out_bh;
  276. }
  277. /* free segments */
  278. for (i = 0; i < nsegs; i++) {
  279. kaddr = kmap_atomic(su_bh[i]->b_page, KM_USER0);
  280. su = nilfs_sufile_block_get_segment_usage(
  281. sufile, segnum[i], su_bh[i], kaddr);
  282. WARN_ON(nilfs_segment_usage_error(su));
  283. nilfs_segment_usage_set_clean(su);
  284. kunmap_atomic(kaddr, KM_USER0);
  285. nilfs_mdt_mark_buffer_dirty(su_bh[i]);
  286. }
  287. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  288. header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr);
  289. le64_add_cpu(&header->sh_ncleansegs, nsegs);
  290. le64_add_cpu(&header->sh_ndirtysegs, -(u64)nsegs);
  291. kunmap_atomic(kaddr, KM_USER0);
  292. nilfs_mdt_mark_buffer_dirty(header_bh);
  293. nilfs_mdt_mark_dirty(sufile);
  294. out_bh:
  295. for (i--; i >= 0; i--)
  296. brelse(su_bh[i]);
  297. brelse(header_bh);
  298. out_su_bh:
  299. if (su_bh != su_bh_prealloc)
  300. kfree(su_bh);
  301. out_sem:
  302. up_write(&NILFS_MDT(sufile)->mi_sem);
  303. return ret;
  304. }
  305. /**
  306. * nilfs_sufile_free -
  307. * @sufile:
  308. * @segnum:
  309. */
  310. int nilfs_sufile_free(struct inode *sufile, __u64 segnum)
  311. {
  312. return nilfs_sufile_freev(sufile, &segnum, 1);
  313. }
  314. /**
  315. * nilfs_sufile_get_segment_usage - get a segment usage
  316. * @sufile: inode of segment usage file
  317. * @segnum: segment number
  318. * @sup: pointer to segment usage
  319. * @bhp: pointer to buffer head
  320. *
  321. * Description: nilfs_sufile_get_segment_usage() acquires the segment usage
  322. * specified by @segnum.
  323. *
  324. * Return Value: On success, 0 is returned, and the segment usage and the
  325. * buffer head of the buffer on which the segment usage is located are stored
  326. * in the place pointed by @sup and @bhp, respectively. On error, one of the
  327. * following negative error codes is returned.
  328. *
  329. * %-EIO - I/O error.
  330. *
  331. * %-ENOMEM - Insufficient amount of memory available.
  332. *
  333. * %-EINVAL - Invalid segment usage number.
  334. */
  335. int nilfs_sufile_get_segment_usage(struct inode *sufile, __u64 segnum,
  336. struct nilfs_segment_usage **sup,
  337. struct buffer_head **bhp)
  338. {
  339. struct buffer_head *bh;
  340. struct nilfs_segment_usage *su;
  341. void *kaddr;
  342. int ret;
  343. /* segnum is 0 origin */
  344. if (segnum >= nilfs_sufile_get_nsegments(sufile))
  345. return -EINVAL;
  346. down_write(&NILFS_MDT(sufile)->mi_sem);
  347. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1, &bh);
  348. if (ret < 0)
  349. goto out_sem;
  350. kaddr = kmap(bh->b_page);
  351. su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
  352. if (nilfs_segment_usage_error(su)) {
  353. kunmap(bh->b_page);
  354. brelse(bh);
  355. ret = -EINVAL;
  356. goto out_sem;
  357. }
  358. if (sup != NULL)
  359. *sup = su;
  360. *bhp = bh;
  361. out_sem:
  362. up_write(&NILFS_MDT(sufile)->mi_sem);
  363. return ret;
  364. }
  365. /**
  366. * nilfs_sufile_put_segment_usage - put a segment usage
  367. * @sufile: inode of segment usage file
  368. * @segnum: segment number
  369. * @bh: buffer head
  370. *
  371. * Description: nilfs_sufile_put_segment_usage() releases the segment usage
  372. * specified by @segnum. @bh must be the buffer head which have been returned
  373. * by a previous call to nilfs_sufile_get_segment_usage() with @segnum.
  374. */
  375. void nilfs_sufile_put_segment_usage(struct inode *sufile, __u64 segnum,
  376. struct buffer_head *bh)
  377. {
  378. kunmap(bh->b_page);
  379. brelse(bh);
  380. }
  381. /**
  382. * nilfs_sufile_get_stat - get segment usage statistics
  383. * @sufile: inode of segment usage file
  384. * @stat: pointer to a structure of segment usage statistics
  385. *
  386. * Description: nilfs_sufile_get_stat() returns information about segment
  387. * usage.
  388. *
  389. * Return Value: On success, 0 is returned, and segment usage information is
  390. * stored in the place pointed by @stat. On error, one of the following
  391. * negative error codes is returned.
  392. *
  393. * %-EIO - I/O error.
  394. *
  395. * %-ENOMEM - Insufficient amount of memory available.
  396. */
  397. int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat)
  398. {
  399. struct buffer_head *header_bh;
  400. struct nilfs_sufile_header *header;
  401. struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
  402. void *kaddr;
  403. int ret;
  404. down_read(&NILFS_MDT(sufile)->mi_sem);
  405. ret = nilfs_sufile_get_header_block(sufile, &header_bh);
  406. if (ret < 0)
  407. goto out_sem;
  408. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  409. header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr);
  410. sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile);
  411. sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs);
  412. sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs);
  413. sustat->ss_ctime = nilfs->ns_ctime;
  414. sustat->ss_nongc_ctime = nilfs->ns_nongc_ctime;
  415. spin_lock(&nilfs->ns_last_segment_lock);
  416. sustat->ss_prot_seq = nilfs->ns_prot_seq;
  417. spin_unlock(&nilfs->ns_last_segment_lock);
  418. kunmap_atomic(kaddr, KM_USER0);
  419. brelse(header_bh);
  420. out_sem:
  421. up_read(&NILFS_MDT(sufile)->mi_sem);
  422. return ret;
  423. }
  424. /**
  425. * nilfs_sufile_get_ncleansegs - get the number of clean segments
  426. * @sufile: inode of segment usage file
  427. * @nsegsp: pointer to the number of clean segments
  428. *
  429. * Description: nilfs_sufile_get_ncleansegs() acquires the number of clean
  430. * segments.
  431. *
  432. * Return Value: On success, 0 is returned and the number of clean segments is
  433. * stored in the place pointed by @nsegsp. On error, one of the following
  434. * negative error codes is returned.
  435. *
  436. * %-EIO - I/O error.
  437. *
  438. * %-ENOMEM - Insufficient amount of memory available.
  439. */
  440. int nilfs_sufile_get_ncleansegs(struct inode *sufile, unsigned long *nsegsp)
  441. {
  442. struct nilfs_sustat sustat;
  443. int ret;
  444. ret = nilfs_sufile_get_stat(sufile, &sustat);
  445. if (ret == 0)
  446. *nsegsp = sustat.ss_ncleansegs;
  447. return ret;
  448. }
  449. /**
  450. * nilfs_sufile_set_error - mark a segment as erroneous
  451. * @sufile: inode of segment usage file
  452. * @segnum: segment number
  453. *
  454. * Description: nilfs_sufile_set_error() marks the segment specified by
  455. * @segnum as erroneous. The error segment will never be used again.
  456. *
  457. * Return Value: On success, 0 is returned. On error, one of the following
  458. * negative error codes is returned.
  459. *
  460. * %-EIO - I/O error.
  461. *
  462. * %-ENOMEM - Insufficient amount of memory available.
  463. *
  464. * %-EINVAL - Invalid segment usage number.
  465. */
  466. int nilfs_sufile_set_error(struct inode *sufile, __u64 segnum)
  467. {
  468. struct buffer_head *header_bh, *su_bh;
  469. struct nilfs_segment_usage *su;
  470. struct nilfs_sufile_header *header;
  471. void *kaddr;
  472. int ret;
  473. if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) {
  474. printk(KERN_WARNING "%s: invalid segment number: %llu\n",
  475. __func__, (unsigned long long)segnum);
  476. return -EINVAL;
  477. }
  478. down_write(&NILFS_MDT(sufile)->mi_sem);
  479. ret = nilfs_sufile_get_header_block(sufile, &header_bh);
  480. if (ret < 0)
  481. goto out_sem;
  482. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &su_bh);
  483. if (ret < 0)
  484. goto out_header;
  485. kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
  486. su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
  487. if (nilfs_segment_usage_error(su)) {
  488. kunmap_atomic(kaddr, KM_USER0);
  489. brelse(su_bh);
  490. goto out_header;
  491. }
  492. nilfs_segment_usage_set_error(su);
  493. kunmap_atomic(kaddr, KM_USER0);
  494. brelse(su_bh);
  495. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  496. header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr);
  497. le64_add_cpu(&header->sh_ndirtysegs, -1);
  498. kunmap_atomic(kaddr, KM_USER0);
  499. nilfs_mdt_mark_buffer_dirty(header_bh);
  500. nilfs_mdt_mark_buffer_dirty(su_bh);
  501. nilfs_mdt_mark_dirty(sufile);
  502. brelse(su_bh);
  503. out_header:
  504. brelse(header_bh);
  505. out_sem:
  506. up_write(&NILFS_MDT(sufile)->mi_sem);
  507. return ret;
  508. }
  509. /**
  510. * nilfs_sufile_get_suinfo -
  511. * @sufile: inode of segment usage file
  512. * @segnum: segment number to start looking
  513. * @si: array of suinfo
  514. * @nsi: size of suinfo array
  515. *
  516. * Description:
  517. *
  518. * Return Value: On success, 0 is returned and .... On error, one of the
  519. * following negative error codes is returned.
  520. *
  521. * %-EIO - I/O error.
  522. *
  523. * %-ENOMEM - Insufficient amount of memory available.
  524. */
  525. ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum,
  526. struct nilfs_suinfo *si, size_t nsi)
  527. {
  528. struct buffer_head *su_bh;
  529. struct nilfs_segment_usage *su;
  530. size_t susz = NILFS_MDT(sufile)->mi_entry_size;
  531. struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
  532. void *kaddr;
  533. unsigned long nsegs, segusages_per_block;
  534. ssize_t n;
  535. int ret, i, j;
  536. down_read(&NILFS_MDT(sufile)->mi_sem);
  537. segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
  538. nsegs = min_t(unsigned long,
  539. nilfs_sufile_get_nsegments(sufile) - segnum,
  540. nsi);
  541. for (i = 0; i < nsegs; i += n, segnum += n) {
  542. n = min_t(unsigned long,
  543. segusages_per_block -
  544. nilfs_sufile_get_offset(sufile, segnum),
  545. nsegs - i);
  546. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
  547. &su_bh);
  548. if (ret < 0) {
  549. if (ret != -ENOENT)
  550. goto out;
  551. /* hole */
  552. memset(&si[i], 0, sizeof(struct nilfs_suinfo) * n);
  553. continue;
  554. }
  555. kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
  556. su = nilfs_sufile_block_get_segment_usage(
  557. sufile, segnum, su_bh, kaddr);
  558. for (j = 0; j < n; j++, su = (void *)su + susz) {
  559. si[i + j].sui_lastmod = le64_to_cpu(su->su_lastmod);
  560. si[i + j].sui_nblocks = le32_to_cpu(su->su_nblocks);
  561. si[i + j].sui_flags = le32_to_cpu(su->su_flags) &
  562. ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
  563. if (nilfs_segment_is_active(nilfs, segnum + i + j))
  564. si[i + j].sui_flags |=
  565. (1UL << NILFS_SEGMENT_USAGE_ACTIVE);
  566. }
  567. kunmap_atomic(kaddr, KM_USER0);
  568. brelse(su_bh);
  569. }
  570. ret = nsegs;
  571. out:
  572. up_read(&NILFS_MDT(sufile)->mi_sem);
  573. return ret;
  574. }