nilfs2: move routine marking segment usage dirty into sufile
[firefly-linux-kernel-4.4.55.git] / fs / nilfs2 / sufile.c
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  * Rivised by Ryusuke Konishi <ryusuke@osrg.net>.
22  */
23
24 #include <linux/kernel.h>
25 #include <linux/fs.h>
26 #include <linux/string.h>
27 #include <linux/buffer_head.h>
28 #include <linux/errno.h>
29 #include <linux/nilfs2_fs.h>
30 #include "mdt.h"
31 #include "sufile.h"
32
33
34 struct nilfs_sufile_info {
35         struct nilfs_mdt_info mi;
36         unsigned long ncleansegs;
37 };
38
39 static inline struct nilfs_sufile_info *NILFS_SUI(struct inode *sufile)
40 {
41         return (struct nilfs_sufile_info *)NILFS_MDT(sufile);
42 }
43
44 static inline unsigned long
45 nilfs_sufile_segment_usages_per_block(const struct inode *sufile)
46 {
47         return NILFS_MDT(sufile)->mi_entries_per_block;
48 }
49
50 static unsigned long
51 nilfs_sufile_get_blkoff(const struct inode *sufile, __u64 segnum)
52 {
53         __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset;
54         do_div(t, nilfs_sufile_segment_usages_per_block(sufile));
55         return (unsigned long)t;
56 }
57
58 static unsigned long
59 nilfs_sufile_get_offset(const struct inode *sufile, __u64 segnum)
60 {
61         __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset;
62         return do_div(t, nilfs_sufile_segment_usages_per_block(sufile));
63 }
64
65 static unsigned long
66 nilfs_sufile_segment_usages_in_block(const struct inode *sufile, __u64 curr,
67                                      __u64 max)
68 {
69         return min_t(unsigned long,
70                      nilfs_sufile_segment_usages_per_block(sufile) -
71                      nilfs_sufile_get_offset(sufile, curr),
72                      max - curr + 1);
73 }
74
75 static struct nilfs_segment_usage *
76 nilfs_sufile_block_get_segment_usage(const struct inode *sufile, __u64 segnum,
77                                      struct buffer_head *bh, void *kaddr)
78 {
79         return kaddr + bh_offset(bh) +
80                 nilfs_sufile_get_offset(sufile, segnum) *
81                 NILFS_MDT(sufile)->mi_entry_size;
82 }
83
84 static inline int nilfs_sufile_get_header_block(struct inode *sufile,
85                                                 struct buffer_head **bhp)
86 {
87         return nilfs_mdt_get_block(sufile, 0, 0, NULL, bhp);
88 }
89
90 static inline int
91 nilfs_sufile_get_segment_usage_block(struct inode *sufile, __u64 segnum,
92                                      int create, struct buffer_head **bhp)
93 {
94         return nilfs_mdt_get_block(sufile,
95                                    nilfs_sufile_get_blkoff(sufile, segnum),
96                                    create, NULL, bhp);
97 }
98
99 static void nilfs_sufile_mod_counter(struct buffer_head *header_bh,
100                                      u64 ncleanadd, u64 ndirtyadd)
101 {
102         struct nilfs_sufile_header *header;
103         void *kaddr;
104
105         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
106         header = kaddr + bh_offset(header_bh);
107         le64_add_cpu(&header->sh_ncleansegs, ncleanadd);
108         le64_add_cpu(&header->sh_ndirtysegs, ndirtyadd);
109         kunmap_atomic(kaddr, KM_USER0);
110
111         nilfs_mdt_mark_buffer_dirty(header_bh);
112 }
113
114 /**
115  * nilfs_sufile_get_ncleansegs - return the number of clean segments
116  * @sufile: inode of segment usage file
117  */
118 unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile)
119 {
120         return NILFS_SUI(sufile)->ncleansegs;
121 }
122
123 /**
124  * nilfs_sufile_updatev - modify multiple segment usages at a time
125  * @sufile: inode of segment usage file
126  * @segnumv: array of segment numbers
127  * @nsegs: size of @segnumv array
128  * @create: creation flag
129  * @ndone: place to store number of modified segments on @segnumv
130  * @dofunc: primitive operation for the update
131  *
132  * Description: nilfs_sufile_updatev() repeatedly calls @dofunc
133  * against the given array of segments.  The @dofunc is called with
134  * buffers of a header block and the sufile block in which the target
135  * segment usage entry is contained.  If @ndone is given, the number
136  * of successfully modified segments from the head is stored in the
137  * place @ndone points to.
138  *
139  * Return Value: On success, zero is returned.  On error, one of the
140  * following negative error codes is returned.
141  *
142  * %-EIO - I/O error.
143  *
144  * %-ENOMEM - Insufficient amount of memory available.
145  *
146  * %-ENOENT - Given segment usage is in hole block (may be returned if
147  *            @create is zero)
148  *
149  * %-EINVAL - Invalid segment usage number
150  */
151 int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
152                          int create, size_t *ndone,
153                          void (*dofunc)(struct inode *, __u64,
154                                         struct buffer_head *,
155                                         struct buffer_head *))
156 {
157         struct buffer_head *header_bh, *bh;
158         unsigned long blkoff, prev_blkoff;
159         __u64 *seg;
160         size_t nerr = 0, n = 0;
161         int ret = 0;
162
163         if (unlikely(nsegs == 0))
164                 goto out;
165
166         down_write(&NILFS_MDT(sufile)->mi_sem);
167         for (seg = segnumv; seg < segnumv + nsegs; seg++) {
168                 if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
169                         printk(KERN_WARNING
170                                "%s: invalid segment number: %llu\n", __func__,
171                                (unsigned long long)*seg);
172                         nerr++;
173                 }
174         }
175         if (nerr > 0) {
176                 ret = -EINVAL;
177                 goto out_sem;
178         }
179
180         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
181         if (ret < 0)
182                 goto out_sem;
183
184         seg = segnumv;
185         blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
186         ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
187         if (ret < 0)
188                 goto out_header;
189
190         for (;;) {
191                 dofunc(sufile, *seg, header_bh, bh);
192
193                 if (++seg >= segnumv + nsegs)
194                         break;
195                 prev_blkoff = blkoff;
196                 blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
197                 if (blkoff == prev_blkoff)
198                         continue;
199
200                 /* get different block */
201                 brelse(bh);
202                 ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
203                 if (unlikely(ret < 0))
204                         goto out_header;
205         }
206         brelse(bh);
207
208  out_header:
209         n = seg - segnumv;
210         brelse(header_bh);
211  out_sem:
212         up_write(&NILFS_MDT(sufile)->mi_sem);
213  out:
214         if (ndone)
215                 *ndone = n;
216         return ret;
217 }
218
219 int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
220                         void (*dofunc)(struct inode *, __u64,
221                                        struct buffer_head *,
222                                        struct buffer_head *))
223 {
224         struct buffer_head *header_bh, *bh;
225         int ret;
226
227         if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) {
228                 printk(KERN_WARNING "%s: invalid segment number: %llu\n",
229                        __func__, (unsigned long long)segnum);
230                 return -EINVAL;
231         }
232         down_write(&NILFS_MDT(sufile)->mi_sem);
233
234         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
235         if (ret < 0)
236                 goto out_sem;
237
238         ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, create, &bh);
239         if (!ret) {
240                 dofunc(sufile, segnum, header_bh, bh);
241                 brelse(bh);
242         }
243         brelse(header_bh);
244
245  out_sem:
246         up_write(&NILFS_MDT(sufile)->mi_sem);
247         return ret;
248 }
249
250 /**
251  * nilfs_sufile_alloc - allocate a segment
252  * @sufile: inode of segment usage file
253  * @segnump: pointer to segment number
254  *
255  * Description: nilfs_sufile_alloc() allocates a clean segment.
256  *
257  * Return Value: On success, 0 is returned and the segment number of the
258  * allocated segment is stored in the place pointed by @segnump. On error, one
259  * of the following negative error codes is returned.
260  *
261  * %-EIO - I/O error.
262  *
263  * %-ENOMEM - Insufficient amount of memory available.
264  *
265  * %-ENOSPC - No clean segment left.
266  */
267 int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump)
268 {
269         struct buffer_head *header_bh, *su_bh;
270         struct nilfs_sufile_header *header;
271         struct nilfs_segment_usage *su;
272         size_t susz = NILFS_MDT(sufile)->mi_entry_size;
273         __u64 segnum, maxsegnum, last_alloc;
274         void *kaddr;
275         unsigned long nsegments, ncleansegs, nsus;
276         int ret, i, j;
277
278         down_write(&NILFS_MDT(sufile)->mi_sem);
279
280         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
281         if (ret < 0)
282                 goto out_sem;
283         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
284         header = kaddr + bh_offset(header_bh);
285         ncleansegs = le64_to_cpu(header->sh_ncleansegs);
286         last_alloc = le64_to_cpu(header->sh_last_alloc);
287         kunmap_atomic(kaddr, KM_USER0);
288
289         nsegments = nilfs_sufile_get_nsegments(sufile);
290         segnum = last_alloc + 1;
291         maxsegnum = nsegments - 1;
292         for (i = 0; i < nsegments; i += nsus) {
293                 if (segnum >= nsegments) {
294                         /* wrap around */
295                         segnum = 0;
296                         maxsegnum = last_alloc;
297                 }
298                 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1,
299                                                            &su_bh);
300                 if (ret < 0)
301                         goto out_header;
302                 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
303                 su = nilfs_sufile_block_get_segment_usage(
304                         sufile, segnum, su_bh, kaddr);
305
306                 nsus = nilfs_sufile_segment_usages_in_block(
307                         sufile, segnum, maxsegnum);
308                 for (j = 0; j < nsus; j++, su = (void *)su + susz, segnum++) {
309                         if (!nilfs_segment_usage_clean(su))
310                                 continue;
311                         /* found a clean segment */
312                         nilfs_segment_usage_set_dirty(su);
313                         kunmap_atomic(kaddr, KM_USER0);
314
315                         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
316                         header = kaddr + bh_offset(header_bh);
317                         le64_add_cpu(&header->sh_ncleansegs, -1);
318                         le64_add_cpu(&header->sh_ndirtysegs, 1);
319                         header->sh_last_alloc = cpu_to_le64(segnum);
320                         kunmap_atomic(kaddr, KM_USER0);
321
322                         NILFS_SUI(sufile)->ncleansegs--;
323                         nilfs_mdt_mark_buffer_dirty(header_bh);
324                         nilfs_mdt_mark_buffer_dirty(su_bh);
325                         nilfs_mdt_mark_dirty(sufile);
326                         brelse(su_bh);
327                         *segnump = segnum;
328                         goto out_header;
329                 }
330
331                 kunmap_atomic(kaddr, KM_USER0);
332                 brelse(su_bh);
333         }
334
335         /* no segments left */
336         ret = -ENOSPC;
337
338  out_header:
339         brelse(header_bh);
340
341  out_sem:
342         up_write(&NILFS_MDT(sufile)->mi_sem);
343         return ret;
344 }
345
346 void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
347                                  struct buffer_head *header_bh,
348                                  struct buffer_head *su_bh)
349 {
350         struct nilfs_segment_usage *su;
351         void *kaddr;
352
353         kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
354         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
355         if (unlikely(!nilfs_segment_usage_clean(su))) {
356                 printk(KERN_WARNING "%s: segment %llu must be clean\n",
357                        __func__, (unsigned long long)segnum);
358                 kunmap_atomic(kaddr, KM_USER0);
359                 return;
360         }
361         nilfs_segment_usage_set_dirty(su);
362         kunmap_atomic(kaddr, KM_USER0);
363
364         nilfs_sufile_mod_counter(header_bh, -1, 1);
365         NILFS_SUI(sufile)->ncleansegs--;
366
367         nilfs_mdt_mark_buffer_dirty(su_bh);
368         nilfs_mdt_mark_dirty(sufile);
369 }
370
371 void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
372                            struct buffer_head *header_bh,
373                            struct buffer_head *su_bh)
374 {
375         struct nilfs_segment_usage *su;
376         void *kaddr;
377         int clean, dirty;
378
379         kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
380         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
381         if (su->su_flags == cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY) &&
382             su->su_nblocks == cpu_to_le32(0)) {
383                 kunmap_atomic(kaddr, KM_USER0);
384                 return;
385         }
386         clean = nilfs_segment_usage_clean(su);
387         dirty = nilfs_segment_usage_dirty(su);
388
389         /* make the segment garbage */
390         su->su_lastmod = cpu_to_le64(0);
391         su->su_nblocks = cpu_to_le32(0);
392         su->su_flags = cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY);
393         kunmap_atomic(kaddr, KM_USER0);
394
395         nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1);
396         NILFS_SUI(sufile)->ncleansegs -= clean;
397
398         nilfs_mdt_mark_buffer_dirty(su_bh);
399         nilfs_mdt_mark_dirty(sufile);
400 }
401
402 void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
403                           struct buffer_head *header_bh,
404                           struct buffer_head *su_bh)
405 {
406         struct nilfs_segment_usage *su;
407         void *kaddr;
408         int sudirty;
409
410         kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
411         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
412         if (nilfs_segment_usage_clean(su)) {
413                 printk(KERN_WARNING "%s: segment %llu is already clean\n",
414                        __func__, (unsigned long long)segnum);
415                 kunmap_atomic(kaddr, KM_USER0);
416                 return;
417         }
418         WARN_ON(nilfs_segment_usage_error(su));
419         WARN_ON(!nilfs_segment_usage_dirty(su));
420
421         sudirty = nilfs_segment_usage_dirty(su);
422         nilfs_segment_usage_set_clean(su);
423         kunmap_atomic(kaddr, KM_USER0);
424         nilfs_mdt_mark_buffer_dirty(su_bh);
425
426         nilfs_sufile_mod_counter(header_bh, 1, sudirty ? (u64)-1 : 0);
427         NILFS_SUI(sufile)->ncleansegs++;
428
429         nilfs_mdt_mark_dirty(sufile);
430 }
431
432 /**
433  * nilfs_sufile_get_segment_usage - get a segment usage
434  * @sufile: inode of segment usage file
435  * @segnum: segment number
436  * @sup: pointer to segment usage
437  * @bhp: pointer to buffer head
438  *
439  * Description: nilfs_sufile_get_segment_usage() acquires the segment usage
440  * specified by @segnum.
441  *
442  * Return Value: On success, 0 is returned, and the segment usage and the
443  * buffer head of the buffer on which the segment usage is located are stored
444  * in the place pointed by @sup and @bhp, respectively. On error, one of the
445  * following negative error codes is returned.
446  *
447  * %-EIO - I/O error.
448  *
449  * %-ENOMEM - Insufficient amount of memory available.
450  *
451  * %-EINVAL - Invalid segment usage number.
452  */
453 int nilfs_sufile_get_segment_usage(struct inode *sufile, __u64 segnum,
454                                    struct nilfs_segment_usage **sup,
455                                    struct buffer_head **bhp)
456 {
457         struct buffer_head *bh;
458         struct nilfs_segment_usage *su;
459         void *kaddr;
460         int ret;
461
462         /* segnum is 0 origin */
463         if (segnum >= nilfs_sufile_get_nsegments(sufile))
464                 return -EINVAL;
465         down_write(&NILFS_MDT(sufile)->mi_sem);
466         ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1, &bh);
467         if (ret < 0)
468                 goto out_sem;
469         kaddr = kmap(bh->b_page);
470         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
471         if (nilfs_segment_usage_error(su)) {
472                 kunmap(bh->b_page);
473                 brelse(bh);
474                 ret = -EINVAL;
475                 goto out_sem;
476         }
477
478         if (sup != NULL)
479                 *sup = su;
480         *bhp = bh;
481
482  out_sem:
483         up_write(&NILFS_MDT(sufile)->mi_sem);
484         return ret;
485 }
486
487 /**
488  * nilfs_sufile_put_segment_usage - put a segment usage
489  * @sufile: inode of segment usage file
490  * @segnum: segment number
491  * @bh: buffer head
492  *
493  * Description: nilfs_sufile_put_segment_usage() releases the segment usage
494  * specified by @segnum. @bh must be the buffer head which have been returned
495  * by a previous call to nilfs_sufile_get_segment_usage() with @segnum.
496  */
497 void nilfs_sufile_put_segment_usage(struct inode *sufile, __u64 segnum,
498                                     struct buffer_head *bh)
499 {
500         kunmap(bh->b_page);
501         brelse(bh);
502 }
503
504 /**
505  * nilfs_sufile_mark_dirty - mark the buffer having a segment usage dirty
506  * @sufile: inode of segment usage file
507  * @segnum: segment number
508  */
509 int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum)
510 {
511         struct buffer_head *bh;
512         int ret;
513
514         ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
515         if (!ret) {
516                 nilfs_mdt_mark_buffer_dirty(bh);
517                 nilfs_mdt_mark_dirty(sufile);
518                 brelse(bh);
519         }
520         return ret;
521 }
522
523 /**
524  * nilfs_sufile_get_stat - get segment usage statistics
525  * @sufile: inode of segment usage file
526  * @stat: pointer to a structure of segment usage statistics
527  *
528  * Description: nilfs_sufile_get_stat() returns information about segment
529  * usage.
530  *
531  * Return Value: On success, 0 is returned, and segment usage information is
532  * stored in the place pointed by @stat. On error, one of the following
533  * negative error codes is returned.
534  *
535  * %-EIO - I/O error.
536  *
537  * %-ENOMEM - Insufficient amount of memory available.
538  */
539 int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat)
540 {
541         struct buffer_head *header_bh;
542         struct nilfs_sufile_header *header;
543         struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
544         void *kaddr;
545         int ret;
546
547         down_read(&NILFS_MDT(sufile)->mi_sem);
548
549         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
550         if (ret < 0)
551                 goto out_sem;
552
553         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
554         header = kaddr + bh_offset(header_bh);
555         sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile);
556         sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs);
557         sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs);
558         sustat->ss_ctime = nilfs->ns_ctime;
559         sustat->ss_nongc_ctime = nilfs->ns_nongc_ctime;
560         spin_lock(&nilfs->ns_last_segment_lock);
561         sustat->ss_prot_seq = nilfs->ns_prot_seq;
562         spin_unlock(&nilfs->ns_last_segment_lock);
563         kunmap_atomic(kaddr, KM_USER0);
564         brelse(header_bh);
565
566  out_sem:
567         up_read(&NILFS_MDT(sufile)->mi_sem);
568         return ret;
569 }
570
571 void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
572                                struct buffer_head *header_bh,
573                                struct buffer_head *su_bh)
574 {
575         struct nilfs_segment_usage *su;
576         void *kaddr;
577         int suclean;
578
579         kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
580         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
581         if (nilfs_segment_usage_error(su)) {
582                 kunmap_atomic(kaddr, KM_USER0);
583                 return;
584         }
585         suclean = nilfs_segment_usage_clean(su);
586         nilfs_segment_usage_set_error(su);
587         kunmap_atomic(kaddr, KM_USER0);
588
589         if (suclean) {
590                 nilfs_sufile_mod_counter(header_bh, -1, 0);
591                 NILFS_SUI(sufile)->ncleansegs--;
592         }
593         nilfs_mdt_mark_buffer_dirty(su_bh);
594         nilfs_mdt_mark_dirty(sufile);
595 }
596
597 /**
598  * nilfs_sufile_get_suinfo -
599  * @sufile: inode of segment usage file
600  * @segnum: segment number to start looking
601  * @buf: array of suinfo
602  * @sisz: byte size of suinfo
603  * @nsi: size of suinfo array
604  *
605  * Description:
606  *
607  * Return Value: On success, 0 is returned and .... On error, one of the
608  * following negative error codes is returned.
609  *
610  * %-EIO - I/O error.
611  *
612  * %-ENOMEM - Insufficient amount of memory available.
613  */
614 ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
615                                 unsigned sisz, size_t nsi)
616 {
617         struct buffer_head *su_bh;
618         struct nilfs_segment_usage *su;
619         struct nilfs_suinfo *si = buf;
620         size_t susz = NILFS_MDT(sufile)->mi_entry_size;
621         struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
622         void *kaddr;
623         unsigned long nsegs, segusages_per_block;
624         ssize_t n;
625         int ret, i, j;
626
627         down_read(&NILFS_MDT(sufile)->mi_sem);
628
629         segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
630         nsegs = min_t(unsigned long,
631                       nilfs_sufile_get_nsegments(sufile) - segnum,
632                       nsi);
633         for (i = 0; i < nsegs; i += n, segnum += n) {
634                 n = min_t(unsigned long,
635                           segusages_per_block -
636                                   nilfs_sufile_get_offset(sufile, segnum),
637                           nsegs - i);
638                 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
639                                                            &su_bh);
640                 if (ret < 0) {
641                         if (ret != -ENOENT)
642                                 goto out;
643                         /* hole */
644                         memset(si, 0, sisz * n);
645                         si = (void *)si + sisz * n;
646                         continue;
647                 }
648
649                 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
650                 su = nilfs_sufile_block_get_segment_usage(
651                         sufile, segnum, su_bh, kaddr);
652                 for (j = 0; j < n;
653                      j++, su = (void *)su + susz, si = (void *)si + sisz) {
654                         si->sui_lastmod = le64_to_cpu(su->su_lastmod);
655                         si->sui_nblocks = le32_to_cpu(su->su_nblocks);
656                         si->sui_flags = le32_to_cpu(su->su_flags) &
657                                 ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
658                         if (nilfs_segment_is_active(nilfs, segnum + j))
659                                 si->sui_flags |=
660                                         (1UL << NILFS_SEGMENT_USAGE_ACTIVE);
661                 }
662                 kunmap_atomic(kaddr, KM_USER0);
663                 brelse(su_bh);
664         }
665         ret = nsegs;
666
667  out:
668         up_read(&NILFS_MDT(sufile)->mi_sem);
669         return ret;
670 }
671
672 /**
673  * nilfs_sufile_read - read sufile inode
674  * @sufile: sufile inode
675  * @raw_inode: on-disk sufile inode
676  */
677 int nilfs_sufile_read(struct inode *sufile, struct nilfs_inode *raw_inode)
678 {
679         struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
680         struct buffer_head *header_bh;
681         struct nilfs_sufile_header *header;
682         void *kaddr;
683         int ret;
684
685         ret = nilfs_read_inode_common(sufile, raw_inode);
686         if (ret < 0)
687                 return ret;
688
689         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
690         if (!ret) {
691                 kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
692                 header = kaddr + bh_offset(header_bh);
693                 sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs);
694                 kunmap_atomic(kaddr, KM_USER0);
695                 brelse(header_bh);
696         }
697         return ret;
698 }
699
700 /**
701  * nilfs_sufile_new - create sufile
702  * @nilfs: nilfs object
703  * @susize: size of a segment usage entry
704  */
705 struct inode *nilfs_sufile_new(struct the_nilfs *nilfs, size_t susize)
706 {
707         struct inode *sufile;
708
709         sufile = nilfs_mdt_new(nilfs, NULL, NILFS_SUFILE_INO,
710                                sizeof(struct nilfs_sufile_info));
711         if (sufile)
712                 nilfs_mdt_set_entry_size(sufile, susize,
713                                          sizeof(struct nilfs_sufile_header));
714         return sufile;
715 }