]> git.karo-electronics.de Git - karo-tx-linux.git/blob - fs/nilfs2/sufile.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[karo-tx-linux.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_mark_dirty - mark the buffer having a segment usage dirty
434  * @sufile: inode of segment usage file
435  * @segnum: segment number
436  */
437 int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum)
438 {
439         struct buffer_head *bh;
440         int ret;
441
442         ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
443         if (!ret) {
444                 nilfs_mdt_mark_buffer_dirty(bh);
445                 nilfs_mdt_mark_dirty(sufile);
446                 brelse(bh);
447         }
448         return ret;
449 }
450
451 /**
452  * nilfs_sufile_set_segment_usage - set usage of a segment
453  * @sufile: inode of segment usage file
454  * @segnum: segment number
455  * @nblocks: number of live blocks in the segment
456  * @modtime: modification time (option)
457  */
458 int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
459                                    unsigned long nblocks, time_t modtime)
460 {
461         struct buffer_head *bh;
462         struct nilfs_segment_usage *su;
463         void *kaddr;
464         int ret;
465
466         down_write(&NILFS_MDT(sufile)->mi_sem);
467         ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
468         if (ret < 0)
469                 goto out_sem;
470
471         kaddr = kmap_atomic(bh->b_page, KM_USER0);
472         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
473         WARN_ON(nilfs_segment_usage_error(su));
474         if (modtime)
475                 su->su_lastmod = cpu_to_le64(modtime);
476         su->su_nblocks = cpu_to_le32(nblocks);
477         kunmap_atomic(kaddr, KM_USER0);
478
479         nilfs_mdt_mark_buffer_dirty(bh);
480         nilfs_mdt_mark_dirty(sufile);
481         brelse(bh);
482
483  out_sem:
484         up_write(&NILFS_MDT(sufile)->mi_sem);
485         return ret;
486 }
487
488 /**
489  * nilfs_sufile_get_stat - get segment usage statistics
490  * @sufile: inode of segment usage file
491  * @stat: pointer to a structure of segment usage statistics
492  *
493  * Description: nilfs_sufile_get_stat() returns information about segment
494  * usage.
495  *
496  * Return Value: On success, 0 is returned, and segment usage information is
497  * stored in the place pointed by @stat. On error, one of the following
498  * negative error codes is returned.
499  *
500  * %-EIO - I/O error.
501  *
502  * %-ENOMEM - Insufficient amount of memory available.
503  */
504 int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat)
505 {
506         struct buffer_head *header_bh;
507         struct nilfs_sufile_header *header;
508         struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
509         void *kaddr;
510         int ret;
511
512         down_read(&NILFS_MDT(sufile)->mi_sem);
513
514         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
515         if (ret < 0)
516                 goto out_sem;
517
518         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
519         header = kaddr + bh_offset(header_bh);
520         sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile);
521         sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs);
522         sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs);
523         sustat->ss_ctime = nilfs->ns_ctime;
524         sustat->ss_nongc_ctime = nilfs->ns_nongc_ctime;
525         spin_lock(&nilfs->ns_last_segment_lock);
526         sustat->ss_prot_seq = nilfs->ns_prot_seq;
527         spin_unlock(&nilfs->ns_last_segment_lock);
528         kunmap_atomic(kaddr, KM_USER0);
529         brelse(header_bh);
530
531  out_sem:
532         up_read(&NILFS_MDT(sufile)->mi_sem);
533         return ret;
534 }
535
536 void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
537                                struct buffer_head *header_bh,
538                                struct buffer_head *su_bh)
539 {
540         struct nilfs_segment_usage *su;
541         void *kaddr;
542         int suclean;
543
544         kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
545         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
546         if (nilfs_segment_usage_error(su)) {
547                 kunmap_atomic(kaddr, KM_USER0);
548                 return;
549         }
550         suclean = nilfs_segment_usage_clean(su);
551         nilfs_segment_usage_set_error(su);
552         kunmap_atomic(kaddr, KM_USER0);
553
554         if (suclean) {
555                 nilfs_sufile_mod_counter(header_bh, -1, 0);
556                 NILFS_SUI(sufile)->ncleansegs--;
557         }
558         nilfs_mdt_mark_buffer_dirty(su_bh);
559         nilfs_mdt_mark_dirty(sufile);
560 }
561
562 /**
563  * nilfs_sufile_get_suinfo -
564  * @sufile: inode of segment usage file
565  * @segnum: segment number to start looking
566  * @buf: array of suinfo
567  * @sisz: byte size of suinfo
568  * @nsi: size of suinfo array
569  *
570  * Description:
571  *
572  * Return Value: On success, 0 is returned and .... On error, one of the
573  * following negative error codes is returned.
574  *
575  * %-EIO - I/O error.
576  *
577  * %-ENOMEM - Insufficient amount of memory available.
578  */
579 ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
580                                 unsigned sisz, size_t nsi)
581 {
582         struct buffer_head *su_bh;
583         struct nilfs_segment_usage *su;
584         struct nilfs_suinfo *si = buf;
585         size_t susz = NILFS_MDT(sufile)->mi_entry_size;
586         struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
587         void *kaddr;
588         unsigned long nsegs, segusages_per_block;
589         ssize_t n;
590         int ret, i, j;
591
592         down_read(&NILFS_MDT(sufile)->mi_sem);
593
594         segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
595         nsegs = min_t(unsigned long,
596                       nilfs_sufile_get_nsegments(sufile) - segnum,
597                       nsi);
598         for (i = 0; i < nsegs; i += n, segnum += n) {
599                 n = min_t(unsigned long,
600                           segusages_per_block -
601                                   nilfs_sufile_get_offset(sufile, segnum),
602                           nsegs - i);
603                 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
604                                                            &su_bh);
605                 if (ret < 0) {
606                         if (ret != -ENOENT)
607                                 goto out;
608                         /* hole */
609                         memset(si, 0, sisz * n);
610                         si = (void *)si + sisz * n;
611                         continue;
612                 }
613
614                 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
615                 su = nilfs_sufile_block_get_segment_usage(
616                         sufile, segnum, su_bh, kaddr);
617                 for (j = 0; j < n;
618                      j++, su = (void *)su + susz, si = (void *)si + sisz) {
619                         si->sui_lastmod = le64_to_cpu(su->su_lastmod);
620                         si->sui_nblocks = le32_to_cpu(su->su_nblocks);
621                         si->sui_flags = le32_to_cpu(su->su_flags) &
622                                 ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
623                         if (nilfs_segment_is_active(nilfs, segnum + j))
624                                 si->sui_flags |=
625                                         (1UL << NILFS_SEGMENT_USAGE_ACTIVE);
626                 }
627                 kunmap_atomic(kaddr, KM_USER0);
628                 brelse(su_bh);
629         }
630         ret = nsegs;
631
632  out:
633         up_read(&NILFS_MDT(sufile)->mi_sem);
634         return ret;
635 }
636
637 /**
638  * nilfs_sufile_read - read sufile inode
639  * @sufile: sufile inode
640  * @raw_inode: on-disk sufile inode
641  */
642 int nilfs_sufile_read(struct inode *sufile, struct nilfs_inode *raw_inode)
643 {
644         struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
645         struct buffer_head *header_bh;
646         struct nilfs_sufile_header *header;
647         void *kaddr;
648         int ret;
649
650         ret = nilfs_read_inode_common(sufile, raw_inode);
651         if (ret < 0)
652                 return ret;
653
654         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
655         if (!ret) {
656                 kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
657                 header = kaddr + bh_offset(header_bh);
658                 sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs);
659                 kunmap_atomic(kaddr, KM_USER0);
660                 brelse(header_bh);
661         }
662         return ret;
663 }
664
665 /**
666  * nilfs_sufile_new - create sufile
667  * @nilfs: nilfs object
668  * @susize: size of a segment usage entry
669  */
670 struct inode *nilfs_sufile_new(struct the_nilfs *nilfs, size_t susize)
671 {
672         struct inode *sufile;
673
674         sufile = nilfs_mdt_new(nilfs, NULL, NILFS_SUFILE_INO,
675                                sizeof(struct nilfs_sufile_info));
676         if (sufile)
677                 nilfs_mdt_set_entry_size(sufile, susize,
678                                          sizeof(struct nilfs_sufile_header));
679         return sufile;
680 }