sufile.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  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_active(su);
  146. nilfs_segment_usage_set_dirty(su);
  147. kunmap_atomic(kaddr, KM_USER0);
  148. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  149. header = nilfs_sufile_block_get_header(
  150. sufile, header_bh, kaddr);
  151. le64_add_cpu(&header->sh_ncleansegs, -1);
  152. le64_add_cpu(&header->sh_ndirtysegs, 1);
  153. header->sh_last_alloc = cpu_to_le64(segnum);
  154. kunmap_atomic(kaddr, KM_USER0);
  155. nilfs_mdt_mark_buffer_dirty(header_bh);
  156. nilfs_mdt_mark_buffer_dirty(su_bh);
  157. nilfs_mdt_mark_dirty(sufile);
  158. brelse(su_bh);
  159. *segnump = segnum;
  160. goto out_header;
  161. }
  162. kunmap_atomic(kaddr, KM_USER0);
  163. brelse(su_bh);
  164. }
  165. /* no segments left */
  166. ret = -ENOSPC;
  167. out_header:
  168. brelse(header_bh);
  169. out_sem:
  170. up_write(&NILFS_MDT(sufile)->mi_sem);
  171. return ret;
  172. }
  173. /**
  174. * nilfs_sufile_cancel_free -
  175. * @sufile: inode of segment usage file
  176. * @segnum: segment number
  177. *
  178. * Description:
  179. *
  180. * Return Value: On success, 0 is returned. On error, one of the following
  181. * negative error codes is returned.
  182. *
  183. * %-EIO - I/O error.
  184. *
  185. * %-ENOMEM - Insufficient amount of memory available.
  186. */
  187. int nilfs_sufile_cancel_free(struct inode *sufile, __u64 segnum)
  188. {
  189. struct buffer_head *header_bh, *su_bh;
  190. struct the_nilfs *nilfs;
  191. struct nilfs_sufile_header *header;
  192. struct nilfs_segment_usage *su;
  193. void *kaddr;
  194. int ret;
  195. down_write(&NILFS_MDT(sufile)->mi_sem);
  196. nilfs = NILFS_MDT(sufile)->mi_nilfs;
  197. ret = nilfs_sufile_get_header_block(sufile, &header_bh);
  198. if (ret < 0)
  199. goto out_sem;
  200. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &su_bh);
  201. if (ret < 0)
  202. goto out_header;
  203. kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
  204. su = nilfs_sufile_block_get_segment_usage(
  205. sufile, segnum, su_bh, kaddr);
  206. if (!nilfs_segment_usage_clean(su)) {
  207. printk(KERN_CRIT "%s: segment %llu must be clean\n",
  208. __func__, (unsigned long long)segnum);
  209. BUG();
  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. brelse(su_bh);
  222. out_header:
  223. brelse(header_bh);
  224. out_sem:
  225. up_write(&NILFS_MDT(sufile)->mi_sem);
  226. return ret;
  227. }
  228. /**
  229. * nilfs_sufile_freev - free segments
  230. * @sufile: inode of segment usage file
  231. * @segnum: array of segment numbers
  232. * @nsegs: number of segments
  233. *
  234. * Description: nilfs_sufile_freev() frees segments specified by @segnum and
  235. * @nsegs, which must have been returned by a previous call to
  236. * nilfs_sufile_alloc().
  237. *
  238. * Return Value: On success, 0 is returned. On error, one of the following
  239. * negative error codes is returned.
  240. *
  241. * %-EIO - I/O error.
  242. *
  243. * %-ENOMEM - Insufficient amount of memory available.
  244. */
  245. #define NILFS_SUFILE_FREEV_PREALLOC 16
  246. int nilfs_sufile_freev(struct inode *sufile, __u64 *segnum, size_t nsegs)
  247. {
  248. struct buffer_head *header_bh, **su_bh,
  249. *su_bh_prealloc[NILFS_SUFILE_FREEV_PREALLOC];
  250. struct the_nilfs *nilfs;
  251. struct nilfs_sufile_header *header;
  252. struct nilfs_segment_usage *su;
  253. void *kaddr;
  254. int ret, i;
  255. down_write(&NILFS_MDT(sufile)->mi_sem);
  256. nilfs = NILFS_MDT(sufile)->mi_nilfs;
  257. /* prepare resources */
  258. if (nsegs <= NILFS_SUFILE_FREEV_PREALLOC)
  259. su_bh = su_bh_prealloc;
  260. else {
  261. su_bh = kmalloc(sizeof(*su_bh) * nsegs, GFP_NOFS);
  262. if (su_bh == NULL) {
  263. ret = -ENOMEM;
  264. goto out_sem;
  265. }
  266. }
  267. ret = nilfs_sufile_get_header_block(sufile, &header_bh);
  268. if (ret < 0)
  269. goto out_su_bh;
  270. for (i = 0; i < nsegs; i++) {
  271. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum[i],
  272. 0, &su_bh[i]);
  273. if (ret < 0)
  274. goto out_bh;
  275. }
  276. /* free segments */
  277. for (i = 0; i < nsegs; i++) {
  278. kaddr = kmap_atomic(su_bh[i]->b_page, KM_USER0);
  279. su = nilfs_sufile_block_get_segment_usage(
  280. sufile, segnum[i], su_bh[i], kaddr);
  281. BUG_ON(nilfs_segment_usage_error(su));
  282. nilfs_segment_usage_set_clean(su);
  283. kunmap_atomic(kaddr, KM_USER0);
  284. nilfs_mdt_mark_buffer_dirty(su_bh[i]);
  285. }
  286. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  287. header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr);
  288. le64_add_cpu(&header->sh_ncleansegs, nsegs);
  289. le64_add_cpu(&header->sh_ndirtysegs, -(u64)nsegs);
  290. kunmap_atomic(kaddr, KM_USER0);
  291. nilfs_mdt_mark_buffer_dirty(header_bh);
  292. nilfs_mdt_mark_dirty(sufile);
  293. out_bh:
  294. for (i--; i >= 0; i--)
  295. brelse(su_bh[i]);
  296. brelse(header_bh);
  297. out_su_bh:
  298. if (su_bh != su_bh_prealloc)
  299. kfree(su_bh);
  300. out_sem:
  301. up_write(&NILFS_MDT(sufile)->mi_sem);
  302. return ret;
  303. }
  304. /**
  305. * nilfs_sufile_free -
  306. * @sufile:
  307. * @segnum:
  308. */
  309. int nilfs_sufile_free(struct inode *sufile, __u64 segnum)
  310. {
  311. return nilfs_sufile_freev(sufile, &segnum, 1);
  312. }
  313. /**
  314. * nilfs_sufile_get_segment_usage - get a segment usage
  315. * @sufile: inode of segment usage file
  316. * @segnum: segment number
  317. * @sup: pointer to segment usage
  318. * @bhp: pointer to buffer head
  319. *
  320. * Description: nilfs_sufile_get_segment_usage() acquires the segment usage
  321. * specified by @segnum.
  322. *
  323. * Return Value: On success, 0 is returned, and the segment usage and the
  324. * buffer head of the buffer on which the segment usage is located are stored
  325. * in the place pointed by @sup and @bhp, respectively. On error, one of the
  326. * following negative error codes is returned.
  327. *
  328. * %-EIO - I/O error.
  329. *
  330. * %-ENOMEM - Insufficient amount of memory available.
  331. *
  332. * %-EINVAL - Invalid segment usage number.
  333. */
  334. int nilfs_sufile_get_segment_usage(struct inode *sufile, __u64 segnum,
  335. struct nilfs_segment_usage **sup,
  336. struct buffer_head **bhp)
  337. {
  338. struct buffer_head *bh;
  339. struct nilfs_segment_usage *su;
  340. void *kaddr;
  341. int ret;
  342. /* segnum is 0 origin */
  343. BUG_ON(segnum >= nilfs_sufile_get_nsegments(sufile));
  344. down_write(&NILFS_MDT(sufile)->mi_sem);
  345. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1, &bh);
  346. if (ret < 0)
  347. goto out_sem;
  348. kaddr = kmap(bh->b_page);
  349. su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
  350. if (nilfs_segment_usage_error(su)) {
  351. kunmap(bh->b_page);
  352. brelse(bh);
  353. ret = -EINVAL;
  354. goto out_sem;
  355. }
  356. if (sup != NULL)
  357. *sup = su;
  358. *bhp = bh;
  359. out_sem:
  360. up_write(&NILFS_MDT(sufile)->mi_sem);
  361. return ret;
  362. }
  363. /**
  364. * nilfs_sufile_put_segment_usage - put a segment usage
  365. * @sufile: inode of segment usage file
  366. * @segnum: segment number
  367. * @bh: buffer head
  368. *
  369. * Description: nilfs_sufile_put_segment_usage() releases the segment usage
  370. * specified by @segnum. @bh must be the buffer head which have been returned
  371. * by a previous call to nilfs_sufile_get_segment_usage() with @segnum.
  372. */
  373. void nilfs_sufile_put_segment_usage(struct inode *sufile, __u64 segnum,
  374. struct buffer_head *bh)
  375. {
  376. kunmap(bh->b_page);
  377. brelse(bh);
  378. }
  379. /**
  380. * nilfs_sufile_get_stat - get segment usage statistics
  381. * @sufile: inode of segment usage file
  382. * @stat: pointer to a structure of segment usage statistics
  383. *
  384. * Description: nilfs_sufile_get_stat() returns information about segment
  385. * usage.
  386. *
  387. * Return Value: On success, 0 is returned, and segment usage information is
  388. * stored in the place pointed by @stat. On error, one of the following
  389. * negative error codes is returned.
  390. *
  391. * %-EIO - I/O error.
  392. *
  393. * %-ENOMEM - Insufficient amount of memory available.
  394. */
  395. int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat)
  396. {
  397. struct buffer_head *header_bh;
  398. struct nilfs_sufile_header *header;
  399. void *kaddr;
  400. int ret;
  401. down_read(&NILFS_MDT(sufile)->mi_sem);
  402. ret = nilfs_sufile_get_header_block(sufile, &header_bh);
  403. if (ret < 0)
  404. goto out_sem;
  405. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  406. header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr);
  407. sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile);
  408. sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs);
  409. sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs);
  410. sustat->ss_ctime = NILFS_MDT(sufile)->mi_nilfs->ns_ctime;
  411. sustat->ss_nongc_ctime = NILFS_MDT(sufile)->mi_nilfs->ns_nongc_ctime;
  412. kunmap_atomic(kaddr, KM_USER0);
  413. brelse(header_bh);
  414. out_sem:
  415. up_read(&NILFS_MDT(sufile)->mi_sem);
  416. return ret;
  417. }
  418. /**
  419. * nilfs_sufile_get_ncleansegs - get the number of clean segments
  420. * @sufile: inode of segment usage file
  421. * @nsegsp: pointer to the number of clean segments
  422. *
  423. * Description: nilfs_sufile_get_ncleansegs() acquires the number of clean
  424. * segments.
  425. *
  426. * Return Value: On success, 0 is returned and the number of clean segments is
  427. * stored in the place pointed by @nsegsp. On error, one of the following
  428. * negative error codes is returned.
  429. *
  430. * %-EIO - I/O error.
  431. *
  432. * %-ENOMEM - Insufficient amount of memory available.
  433. */
  434. int nilfs_sufile_get_ncleansegs(struct inode *sufile, unsigned long *nsegsp)
  435. {
  436. struct nilfs_sustat sustat;
  437. int ret;
  438. ret = nilfs_sufile_get_stat(sufile, &sustat);
  439. if (ret == 0)
  440. *nsegsp = sustat.ss_ncleansegs;
  441. return ret;
  442. }
  443. /**
  444. * nilfs_sufile_set_error - mark a segment as erroneous
  445. * @sufile: inode of segment usage file
  446. * @segnum: segment number
  447. *
  448. * Description: nilfs_sufile_set_error() marks the segment specified by
  449. * @segnum as erroneous. The error segment will never be used again.
  450. *
  451. * Return Value: On success, 0 is returned. On error, one of the following
  452. * negative error codes is returned.
  453. *
  454. * %-EIO - I/O error.
  455. *
  456. * %-ENOMEM - Insufficient amount of memory available.
  457. */
  458. int nilfs_sufile_set_error(struct inode *sufile, __u64 segnum)
  459. {
  460. struct buffer_head *header_bh, *su_bh;
  461. struct nilfs_segment_usage *su;
  462. struct nilfs_sufile_header *header;
  463. void *kaddr;
  464. int ret;
  465. BUG_ON(segnum >= nilfs_sufile_get_nsegments(sufile));
  466. down_write(&NILFS_MDT(sufile)->mi_sem);
  467. ret = nilfs_sufile_get_header_block(sufile, &header_bh);
  468. if (ret < 0)
  469. goto out_sem;
  470. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &su_bh);
  471. if (ret < 0)
  472. goto out_header;
  473. kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
  474. su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
  475. if (nilfs_segment_usage_error(su)) {
  476. kunmap_atomic(kaddr, KM_USER0);
  477. brelse(su_bh);
  478. goto out_header;
  479. }
  480. nilfs_segment_usage_set_error(su);
  481. kunmap_atomic(kaddr, KM_USER0);
  482. brelse(su_bh);
  483. kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
  484. header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr);
  485. le64_add_cpu(&header->sh_ndirtysegs, -1);
  486. kunmap_atomic(kaddr, KM_USER0);
  487. nilfs_mdt_mark_buffer_dirty(header_bh);
  488. nilfs_mdt_mark_buffer_dirty(su_bh);
  489. nilfs_mdt_mark_dirty(sufile);
  490. brelse(su_bh);
  491. out_header:
  492. brelse(header_bh);
  493. out_sem:
  494. up_write(&NILFS_MDT(sufile)->mi_sem);
  495. return ret;
  496. }
  497. /**
  498. * nilfs_sufile_get_suinfo -
  499. * @sufile: inode of segment usage file
  500. * @segnum: segment number to start looking
  501. * @si: array of suinfo
  502. * @nsi: size of suinfo array
  503. *
  504. * Description:
  505. *
  506. * Return Value: On success, 0 is returned and .... On error, one of the
  507. * following negative error codes is returned.
  508. *
  509. * %-EIO - I/O error.
  510. *
  511. * %-ENOMEM - Insufficient amount of memory available.
  512. */
  513. ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum,
  514. struct nilfs_suinfo *si, size_t nsi)
  515. {
  516. struct buffer_head *su_bh;
  517. struct nilfs_segment_usage *su;
  518. size_t susz = NILFS_MDT(sufile)->mi_entry_size;
  519. void *kaddr;
  520. unsigned long nsegs, segusages_per_block;
  521. ssize_t n;
  522. int ret, i, j;
  523. down_read(&NILFS_MDT(sufile)->mi_sem);
  524. segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
  525. nsegs = min_t(unsigned long,
  526. nilfs_sufile_get_nsegments(sufile) - segnum,
  527. nsi);
  528. for (i = 0; i < nsegs; i += n, segnum += n) {
  529. n = min_t(unsigned long,
  530. segusages_per_block -
  531. nilfs_sufile_get_offset(sufile, segnum),
  532. nsegs - i);
  533. ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
  534. &su_bh);
  535. if (ret < 0) {
  536. if (ret != -ENOENT)
  537. goto out;
  538. /* hole */
  539. memset(&si[i], 0, sizeof(struct nilfs_suinfo) * n);
  540. continue;
  541. }
  542. kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
  543. su = nilfs_sufile_block_get_segment_usage(
  544. sufile, segnum, su_bh, kaddr);
  545. for (j = 0; j < n; j++, su = (void *)su + susz) {
  546. si[i + j].sui_lastmod = le64_to_cpu(su->su_lastmod);
  547. si[i + j].sui_nblocks = le32_to_cpu(su->su_nblocks);
  548. si[i + j].sui_flags = le32_to_cpu(su->su_flags);
  549. }
  550. kunmap_atomic(kaddr, KM_USER0);
  551. brelse(su_bh);
  552. }
  553. ret = nsegs;
  554. out:
  555. up_read(&NILFS_MDT(sufile)->mi_sem);
  556. return ret;
  557. }