3eed998df1c80fa2c9aa94141506a719c74b909d
[safe/jmp/linux-2.6] / 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_set_segment_usage - set usage of a segment
525  * @sufile: inode of segment usage file
526  * @segnum: segment number
527  * @nblocks: number of live blocks in the segment
528  * @modtime: modification time (option)
529  */
530 int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
531                                    unsigned long nblocks, time_t modtime)
532 {
533         struct buffer_head *bh;
534         struct nilfs_segment_usage *su;
535         void *kaddr;
536         int ret;
537
538         down_write(&NILFS_MDT(sufile)->mi_sem);
539         ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
540         if (ret < 0)
541                 goto out_sem;
542
543         kaddr = kmap_atomic(bh->b_page, KM_USER0);
544         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
545         WARN_ON(nilfs_segment_usage_error(su));
546         if (modtime)
547                 su->su_lastmod = cpu_to_le64(modtime);
548         su->su_nblocks = cpu_to_le32(nblocks);
549         kunmap_atomic(kaddr, KM_USER0);
550
551         nilfs_mdt_mark_buffer_dirty(bh);
552         nilfs_mdt_mark_dirty(sufile);
553         brelse(bh);
554
555  out_sem:
556         up_write(&NILFS_MDT(sufile)->mi_sem);
557         return ret;
558 }
559
560 /**
561  * nilfs_sufile_get_stat - get segment usage statistics
562  * @sufile: inode of segment usage file
563  * @stat: pointer to a structure of segment usage statistics
564  *
565  * Description: nilfs_sufile_get_stat() returns information about segment
566  * usage.
567  *
568  * Return Value: On success, 0 is returned, and segment usage information is
569  * stored in the place pointed by @stat. On error, one of the following
570  * negative error codes is returned.
571  *
572  * %-EIO - I/O error.
573  *
574  * %-ENOMEM - Insufficient amount of memory available.
575  */
576 int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat)
577 {
578         struct buffer_head *header_bh;
579         struct nilfs_sufile_header *header;
580         struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
581         void *kaddr;
582         int ret;
583
584         down_read(&NILFS_MDT(sufile)->mi_sem);
585
586         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
587         if (ret < 0)
588                 goto out_sem;
589
590         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
591         header = kaddr + bh_offset(header_bh);
592         sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile);
593         sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs);
594         sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs);
595         sustat->ss_ctime = nilfs->ns_ctime;
596         sustat->ss_nongc_ctime = nilfs->ns_nongc_ctime;
597         spin_lock(&nilfs->ns_last_segment_lock);
598         sustat->ss_prot_seq = nilfs->ns_prot_seq;
599         spin_unlock(&nilfs->ns_last_segment_lock);
600         kunmap_atomic(kaddr, KM_USER0);
601         brelse(header_bh);
602
603  out_sem:
604         up_read(&NILFS_MDT(sufile)->mi_sem);
605         return ret;
606 }
607
608 void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
609                                struct buffer_head *header_bh,
610                                struct buffer_head *su_bh)
611 {
612         struct nilfs_segment_usage *su;
613         void *kaddr;
614         int suclean;
615
616         kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
617         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
618         if (nilfs_segment_usage_error(su)) {
619                 kunmap_atomic(kaddr, KM_USER0);
620                 return;
621         }
622         suclean = nilfs_segment_usage_clean(su);
623         nilfs_segment_usage_set_error(su);
624         kunmap_atomic(kaddr, KM_USER0);
625
626         if (suclean) {
627                 nilfs_sufile_mod_counter(header_bh, -1, 0);
628                 NILFS_SUI(sufile)->ncleansegs--;
629         }
630         nilfs_mdt_mark_buffer_dirty(su_bh);
631         nilfs_mdt_mark_dirty(sufile);
632 }
633
634 /**
635  * nilfs_sufile_get_suinfo -
636  * @sufile: inode of segment usage file
637  * @segnum: segment number to start looking
638  * @buf: array of suinfo
639  * @sisz: byte size of suinfo
640  * @nsi: size of suinfo array
641  *
642  * Description:
643  *
644  * Return Value: On success, 0 is returned and .... On error, one of the
645  * following negative error codes is returned.
646  *
647  * %-EIO - I/O error.
648  *
649  * %-ENOMEM - Insufficient amount of memory available.
650  */
651 ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
652                                 unsigned sisz, size_t nsi)
653 {
654         struct buffer_head *su_bh;
655         struct nilfs_segment_usage *su;
656         struct nilfs_suinfo *si = buf;
657         size_t susz = NILFS_MDT(sufile)->mi_entry_size;
658         struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
659         void *kaddr;
660         unsigned long nsegs, segusages_per_block;
661         ssize_t n;
662         int ret, i, j;
663
664         down_read(&NILFS_MDT(sufile)->mi_sem);
665
666         segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
667         nsegs = min_t(unsigned long,
668                       nilfs_sufile_get_nsegments(sufile) - segnum,
669                       nsi);
670         for (i = 0; i < nsegs; i += n, segnum += n) {
671                 n = min_t(unsigned long,
672                           segusages_per_block -
673                                   nilfs_sufile_get_offset(sufile, segnum),
674                           nsegs - i);
675                 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
676                                                            &su_bh);
677                 if (ret < 0) {
678                         if (ret != -ENOENT)
679                                 goto out;
680                         /* hole */
681                         memset(si, 0, sisz * n);
682                         si = (void *)si + sisz * n;
683                         continue;
684                 }
685
686                 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
687                 su = nilfs_sufile_block_get_segment_usage(
688                         sufile, segnum, su_bh, kaddr);
689                 for (j = 0; j < n;
690                      j++, su = (void *)su + susz, si = (void *)si + sisz) {
691                         si->sui_lastmod = le64_to_cpu(su->su_lastmod);
692                         si->sui_nblocks = le32_to_cpu(su->su_nblocks);
693                         si->sui_flags = le32_to_cpu(su->su_flags) &
694                                 ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
695                         if (nilfs_segment_is_active(nilfs, segnum + j))
696                                 si->sui_flags |=
697                                         (1UL << NILFS_SEGMENT_USAGE_ACTIVE);
698                 }
699                 kunmap_atomic(kaddr, KM_USER0);
700                 brelse(su_bh);
701         }
702         ret = nsegs;
703
704  out:
705         up_read(&NILFS_MDT(sufile)->mi_sem);
706         return ret;
707 }
708
709 /**
710  * nilfs_sufile_read - read sufile inode
711  * @sufile: sufile inode
712  * @raw_inode: on-disk sufile inode
713  */
714 int nilfs_sufile_read(struct inode *sufile, struct nilfs_inode *raw_inode)
715 {
716         struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
717         struct buffer_head *header_bh;
718         struct nilfs_sufile_header *header;
719         void *kaddr;
720         int ret;
721
722         ret = nilfs_read_inode_common(sufile, raw_inode);
723         if (ret < 0)
724                 return ret;
725
726         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
727         if (!ret) {
728                 kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
729                 header = kaddr + bh_offset(header_bh);
730                 sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs);
731                 kunmap_atomic(kaddr, KM_USER0);
732                 brelse(header_bh);
733         }
734         return ret;
735 }
736
737 /**
738  * nilfs_sufile_new - create sufile
739  * @nilfs: nilfs object
740  * @susize: size of a segment usage entry
741  */
742 struct inode *nilfs_sufile_new(struct the_nilfs *nilfs, size_t susize)
743 {
744         struct inode *sufile;
745
746         sufile = nilfs_mdt_new(nilfs, NULL, NILFS_SUFILE_INO,
747                                sizeof(struct nilfs_sufile_info));
748         if (sufile)
749                 nilfs_mdt_set_entry_size(sufile, susize,
750                                          sizeof(struct nilfs_sufile_header));
751         return sufile;
752 }