nilfs2: add truncation routine of segment usage file
[linux-2.6.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  * Revised 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;/* number of clean segments */
37         __u64 allocmin;         /* lower limit of allocatable segment range */
38         __u64 allocmax;         /* upper limit of allocatable segment range */
39 };
40
41 static inline struct nilfs_sufile_info *NILFS_SUI(struct inode *sufile)
42 {
43         return (struct nilfs_sufile_info *)NILFS_MDT(sufile);
44 }
45
46 static inline unsigned long
47 nilfs_sufile_segment_usages_per_block(const struct inode *sufile)
48 {
49         return NILFS_MDT(sufile)->mi_entries_per_block;
50 }
51
52 static unsigned long
53 nilfs_sufile_get_blkoff(const struct inode *sufile, __u64 segnum)
54 {
55         __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset;
56         do_div(t, nilfs_sufile_segment_usages_per_block(sufile));
57         return (unsigned long)t;
58 }
59
60 static unsigned long
61 nilfs_sufile_get_offset(const struct inode *sufile, __u64 segnum)
62 {
63         __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset;
64         return do_div(t, nilfs_sufile_segment_usages_per_block(sufile));
65 }
66
67 static unsigned long
68 nilfs_sufile_segment_usages_in_block(const struct inode *sufile, __u64 curr,
69                                      __u64 max)
70 {
71         return min_t(unsigned long,
72                      nilfs_sufile_segment_usages_per_block(sufile) -
73                      nilfs_sufile_get_offset(sufile, curr),
74                      max - curr + 1);
75 }
76
77 static struct nilfs_segment_usage *
78 nilfs_sufile_block_get_segment_usage(const struct inode *sufile, __u64 segnum,
79                                      struct buffer_head *bh, void *kaddr)
80 {
81         return kaddr + bh_offset(bh) +
82                 nilfs_sufile_get_offset(sufile, segnum) *
83                 NILFS_MDT(sufile)->mi_entry_size;
84 }
85
86 static inline int nilfs_sufile_get_header_block(struct inode *sufile,
87                                                 struct buffer_head **bhp)
88 {
89         return nilfs_mdt_get_block(sufile, 0, 0, NULL, bhp);
90 }
91
92 static inline int
93 nilfs_sufile_get_segment_usage_block(struct inode *sufile, __u64 segnum,
94                                      int create, struct buffer_head **bhp)
95 {
96         return nilfs_mdt_get_block(sufile,
97                                    nilfs_sufile_get_blkoff(sufile, segnum),
98                                    create, NULL, bhp);
99 }
100
101 static int nilfs_sufile_delete_segment_usage_block(struct inode *sufile,
102                                                    __u64 segnum)
103 {
104         return nilfs_mdt_delete_block(sufile,
105                                       nilfs_sufile_get_blkoff(sufile, segnum));
106 }
107
108 static void nilfs_sufile_mod_counter(struct buffer_head *header_bh,
109                                      u64 ncleanadd, u64 ndirtyadd)
110 {
111         struct nilfs_sufile_header *header;
112         void *kaddr;
113
114         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
115         header = kaddr + bh_offset(header_bh);
116         le64_add_cpu(&header->sh_ncleansegs, ncleanadd);
117         le64_add_cpu(&header->sh_ndirtysegs, ndirtyadd);
118         kunmap_atomic(kaddr, KM_USER0);
119
120         nilfs_mdt_mark_buffer_dirty(header_bh);
121 }
122
123 /**
124  * nilfs_sufile_get_ncleansegs - return the number of clean segments
125  * @sufile: inode of segment usage file
126  */
127 unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile)
128 {
129         return NILFS_SUI(sufile)->ncleansegs;
130 }
131
132 /**
133  * nilfs_sufile_updatev - modify multiple segment usages at a time
134  * @sufile: inode of segment usage file
135  * @segnumv: array of segment numbers
136  * @nsegs: size of @segnumv array
137  * @create: creation flag
138  * @ndone: place to store number of modified segments on @segnumv
139  * @dofunc: primitive operation for the update
140  *
141  * Description: nilfs_sufile_updatev() repeatedly calls @dofunc
142  * against the given array of segments.  The @dofunc is called with
143  * buffers of a header block and the sufile block in which the target
144  * segment usage entry is contained.  If @ndone is given, the number
145  * of successfully modified segments from the head is stored in the
146  * place @ndone points to.
147  *
148  * Return Value: On success, zero is returned.  On error, one of the
149  * following negative error codes is returned.
150  *
151  * %-EIO - I/O error.
152  *
153  * %-ENOMEM - Insufficient amount of memory available.
154  *
155  * %-ENOENT - Given segment usage is in hole block (may be returned if
156  *            @create is zero)
157  *
158  * %-EINVAL - Invalid segment usage number
159  */
160 int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
161                          int create, size_t *ndone,
162                          void (*dofunc)(struct inode *, __u64,
163                                         struct buffer_head *,
164                                         struct buffer_head *))
165 {
166         struct buffer_head *header_bh, *bh;
167         unsigned long blkoff, prev_blkoff;
168         __u64 *seg;
169         size_t nerr = 0, n = 0;
170         int ret = 0;
171
172         if (unlikely(nsegs == 0))
173                 goto out;
174
175         down_write(&NILFS_MDT(sufile)->mi_sem);
176         for (seg = segnumv; seg < segnumv + nsegs; seg++) {
177                 if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
178                         printk(KERN_WARNING
179                                "%s: invalid segment number: %llu\n", __func__,
180                                (unsigned long long)*seg);
181                         nerr++;
182                 }
183         }
184         if (nerr > 0) {
185                 ret = -EINVAL;
186                 goto out_sem;
187         }
188
189         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
190         if (ret < 0)
191                 goto out_sem;
192
193         seg = segnumv;
194         blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
195         ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
196         if (ret < 0)
197                 goto out_header;
198
199         for (;;) {
200                 dofunc(sufile, *seg, header_bh, bh);
201
202                 if (++seg >= segnumv + nsegs)
203                         break;
204                 prev_blkoff = blkoff;
205                 blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
206                 if (blkoff == prev_blkoff)
207                         continue;
208
209                 /* get different block */
210                 brelse(bh);
211                 ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
212                 if (unlikely(ret < 0))
213                         goto out_header;
214         }
215         brelse(bh);
216
217  out_header:
218         n = seg - segnumv;
219         brelse(header_bh);
220  out_sem:
221         up_write(&NILFS_MDT(sufile)->mi_sem);
222  out:
223         if (ndone)
224                 *ndone = n;
225         return ret;
226 }
227
228 int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
229                         void (*dofunc)(struct inode *, __u64,
230                                        struct buffer_head *,
231                                        struct buffer_head *))
232 {
233         struct buffer_head *header_bh, *bh;
234         int ret;
235
236         if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) {
237                 printk(KERN_WARNING "%s: invalid segment number: %llu\n",
238                        __func__, (unsigned long long)segnum);
239                 return -EINVAL;
240         }
241         down_write(&NILFS_MDT(sufile)->mi_sem);
242
243         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
244         if (ret < 0)
245                 goto out_sem;
246
247         ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, create, &bh);
248         if (!ret) {
249                 dofunc(sufile, segnum, header_bh, bh);
250                 brelse(bh);
251         }
252         brelse(header_bh);
253
254  out_sem:
255         up_write(&NILFS_MDT(sufile)->mi_sem);
256         return ret;
257 }
258
259 /**
260  * nilfs_sufile_set_alloc_range - limit range of segment to be allocated
261  * @sufile: inode of segment usage file
262  * @start: minimum segment number of allocatable region (inclusive)
263  * @end: maximum segment number of allocatable region (inclusive)
264  *
265  * Return Value: On success, 0 is returned.  On error, one of the
266  * following negative error codes is returned.
267  *
268  * %-ERANGE - invalid segment region
269  */
270 int nilfs_sufile_set_alloc_range(struct inode *sufile, __u64 start, __u64 end)
271 {
272         struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
273         __u64 nsegs;
274         int ret = -ERANGE;
275
276         down_write(&NILFS_MDT(sufile)->mi_sem);
277         nsegs = nilfs_sufile_get_nsegments(sufile);
278
279         if (start <= end && end < nsegs) {
280                 sui->allocmin = start;
281                 sui->allocmax = end;
282                 ret = 0;
283         }
284         up_write(&NILFS_MDT(sufile)->mi_sem);
285         return ret;
286 }
287
288 /**
289  * nilfs_sufile_alloc - allocate a segment
290  * @sufile: inode of segment usage file
291  * @segnump: pointer to segment number
292  *
293  * Description: nilfs_sufile_alloc() allocates a clean segment.
294  *
295  * Return Value: On success, 0 is returned and the segment number of the
296  * allocated segment is stored in the place pointed by @segnump. On error, one
297  * of the following negative error codes is returned.
298  *
299  * %-EIO - I/O error.
300  *
301  * %-ENOMEM - Insufficient amount of memory available.
302  *
303  * %-ENOSPC - No clean segment left.
304  */
305 int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump)
306 {
307         struct buffer_head *header_bh, *su_bh;
308         struct nilfs_sufile_header *header;
309         struct nilfs_segment_usage *su;
310         struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
311         size_t susz = NILFS_MDT(sufile)->mi_entry_size;
312         __u64 segnum, maxsegnum, last_alloc;
313         void *kaddr;
314         unsigned long nsegments, ncleansegs, nsus, cnt;
315         int ret, j;
316
317         down_write(&NILFS_MDT(sufile)->mi_sem);
318
319         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
320         if (ret < 0)
321                 goto out_sem;
322         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
323         header = kaddr + bh_offset(header_bh);
324         ncleansegs = le64_to_cpu(header->sh_ncleansegs);
325         last_alloc = le64_to_cpu(header->sh_last_alloc);
326         kunmap_atomic(kaddr, KM_USER0);
327
328         nsegments = nilfs_sufile_get_nsegments(sufile);
329         maxsegnum = sui->allocmax;
330         segnum = last_alloc + 1;
331         if (segnum < sui->allocmin || segnum > sui->allocmax)
332                 segnum = sui->allocmin;
333
334         for (cnt = 0; cnt < nsegments; cnt += nsus) {
335                 if (segnum > maxsegnum) {
336                         if (cnt < sui->allocmax - sui->allocmin + 1) {
337                                 /*
338                                  * wrap around in the limited region.
339                                  * if allocation started from
340                                  * sui->allocmin, this never happens.
341                                  */
342                                 segnum = sui->allocmin;
343                                 maxsegnum = last_alloc;
344                         } else if (segnum > sui->allocmin &&
345                                    sui->allocmax + 1 < nsegments) {
346                                 segnum = sui->allocmax + 1;
347                                 maxsegnum = nsegments - 1;
348                         } else if (sui->allocmin > 0)  {
349                                 segnum = 0;
350                                 maxsegnum = sui->allocmin - 1;
351                         } else {
352                                 break; /* never happens */
353                         }
354                 }
355                 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1,
356                                                            &su_bh);
357                 if (ret < 0)
358                         goto out_header;
359                 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
360                 su = nilfs_sufile_block_get_segment_usage(
361                         sufile, segnum, su_bh, kaddr);
362
363                 nsus = nilfs_sufile_segment_usages_in_block(
364                         sufile, segnum, maxsegnum);
365                 for (j = 0; j < nsus; j++, su = (void *)su + susz, segnum++) {
366                         if (!nilfs_segment_usage_clean(su))
367                                 continue;
368                         /* found a clean segment */
369                         nilfs_segment_usage_set_dirty(su);
370                         kunmap_atomic(kaddr, KM_USER0);
371
372                         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
373                         header = kaddr + bh_offset(header_bh);
374                         le64_add_cpu(&header->sh_ncleansegs, -1);
375                         le64_add_cpu(&header->sh_ndirtysegs, 1);
376                         header->sh_last_alloc = cpu_to_le64(segnum);
377                         kunmap_atomic(kaddr, KM_USER0);
378
379                         sui->ncleansegs--;
380                         nilfs_mdt_mark_buffer_dirty(header_bh);
381                         nilfs_mdt_mark_buffer_dirty(su_bh);
382                         nilfs_mdt_mark_dirty(sufile);
383                         brelse(su_bh);
384                         *segnump = segnum;
385                         goto out_header;
386                 }
387
388                 kunmap_atomic(kaddr, KM_USER0);
389                 brelse(su_bh);
390         }
391
392         /* no segments left */
393         ret = -ENOSPC;
394
395  out_header:
396         brelse(header_bh);
397
398  out_sem:
399         up_write(&NILFS_MDT(sufile)->mi_sem);
400         return ret;
401 }
402
403 void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
404                                  struct buffer_head *header_bh,
405                                  struct buffer_head *su_bh)
406 {
407         struct nilfs_segment_usage *su;
408         void *kaddr;
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 (unlikely(!nilfs_segment_usage_clean(su))) {
413                 printk(KERN_WARNING "%s: segment %llu must be clean\n",
414                        __func__, (unsigned long long)segnum);
415                 kunmap_atomic(kaddr, KM_USER0);
416                 return;
417         }
418         nilfs_segment_usage_set_dirty(su);
419         kunmap_atomic(kaddr, KM_USER0);
420
421         nilfs_sufile_mod_counter(header_bh, -1, 1);
422         NILFS_SUI(sufile)->ncleansegs--;
423
424         nilfs_mdt_mark_buffer_dirty(su_bh);
425         nilfs_mdt_mark_dirty(sufile);
426 }
427
428 void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
429                            struct buffer_head *header_bh,
430                            struct buffer_head *su_bh)
431 {
432         struct nilfs_segment_usage *su;
433         void *kaddr;
434         int clean, dirty;
435
436         kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
437         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
438         if (su->su_flags == cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY) &&
439             su->su_nblocks == cpu_to_le32(0)) {
440                 kunmap_atomic(kaddr, KM_USER0);
441                 return;
442         }
443         clean = nilfs_segment_usage_clean(su);
444         dirty = nilfs_segment_usage_dirty(su);
445
446         /* make the segment garbage */
447         su->su_lastmod = cpu_to_le64(0);
448         su->su_nblocks = cpu_to_le32(0);
449         su->su_flags = cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY);
450         kunmap_atomic(kaddr, KM_USER0);
451
452         nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1);
453         NILFS_SUI(sufile)->ncleansegs -= clean;
454
455         nilfs_mdt_mark_buffer_dirty(su_bh);
456         nilfs_mdt_mark_dirty(sufile);
457 }
458
459 void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
460                           struct buffer_head *header_bh,
461                           struct buffer_head *su_bh)
462 {
463         struct nilfs_segment_usage *su;
464         void *kaddr;
465         int sudirty;
466
467         kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
468         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
469         if (nilfs_segment_usage_clean(su)) {
470                 printk(KERN_WARNING "%s: segment %llu is already clean\n",
471                        __func__, (unsigned long long)segnum);
472                 kunmap_atomic(kaddr, KM_USER0);
473                 return;
474         }
475         WARN_ON(nilfs_segment_usage_error(su));
476         WARN_ON(!nilfs_segment_usage_dirty(su));
477
478         sudirty = nilfs_segment_usage_dirty(su);
479         nilfs_segment_usage_set_clean(su);
480         kunmap_atomic(kaddr, KM_USER0);
481         nilfs_mdt_mark_buffer_dirty(su_bh);
482
483         nilfs_sufile_mod_counter(header_bh, 1, sudirty ? (u64)-1 : 0);
484         NILFS_SUI(sufile)->ncleansegs++;
485
486         nilfs_mdt_mark_dirty(sufile);
487 }
488
489 /**
490  * nilfs_sufile_mark_dirty - mark the buffer having a segment usage dirty
491  * @sufile: inode of segment usage file
492  * @segnum: segment number
493  */
494 int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum)
495 {
496         struct buffer_head *bh;
497         int ret;
498
499         ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
500         if (!ret) {
501                 nilfs_mdt_mark_buffer_dirty(bh);
502                 nilfs_mdt_mark_dirty(sufile);
503                 brelse(bh);
504         }
505         return ret;
506 }
507
508 /**
509  * nilfs_sufile_set_segment_usage - set usage of a segment
510  * @sufile: inode of segment usage file
511  * @segnum: segment number
512  * @nblocks: number of live blocks in the segment
513  * @modtime: modification time (option)
514  */
515 int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
516                                    unsigned long nblocks, time_t modtime)
517 {
518         struct buffer_head *bh;
519         struct nilfs_segment_usage *su;
520         void *kaddr;
521         int ret;
522
523         down_write(&NILFS_MDT(sufile)->mi_sem);
524         ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
525         if (ret < 0)
526                 goto out_sem;
527
528         kaddr = kmap_atomic(bh->b_page, KM_USER0);
529         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
530         WARN_ON(nilfs_segment_usage_error(su));
531         if (modtime)
532                 su->su_lastmod = cpu_to_le64(modtime);
533         su->su_nblocks = cpu_to_le32(nblocks);
534         kunmap_atomic(kaddr, KM_USER0);
535
536         nilfs_mdt_mark_buffer_dirty(bh);
537         nilfs_mdt_mark_dirty(sufile);
538         brelse(bh);
539
540  out_sem:
541         up_write(&NILFS_MDT(sufile)->mi_sem);
542         return ret;
543 }
544
545 /**
546  * nilfs_sufile_get_stat - get segment usage statistics
547  * @sufile: inode of segment usage file
548  * @stat: pointer to a structure of segment usage statistics
549  *
550  * Description: nilfs_sufile_get_stat() returns information about segment
551  * usage.
552  *
553  * Return Value: On success, 0 is returned, and segment usage information is
554  * stored in the place pointed by @stat. On error, one of the following
555  * negative error codes is returned.
556  *
557  * %-EIO - I/O error.
558  *
559  * %-ENOMEM - Insufficient amount of memory available.
560  */
561 int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat)
562 {
563         struct buffer_head *header_bh;
564         struct nilfs_sufile_header *header;
565         struct the_nilfs *nilfs = NILFS_I_NILFS(sufile);
566         void *kaddr;
567         int ret;
568
569         down_read(&NILFS_MDT(sufile)->mi_sem);
570
571         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
572         if (ret < 0)
573                 goto out_sem;
574
575         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
576         header = kaddr + bh_offset(header_bh);
577         sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile);
578         sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs);
579         sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs);
580         sustat->ss_ctime = nilfs->ns_ctime;
581         sustat->ss_nongc_ctime = nilfs->ns_nongc_ctime;
582         spin_lock(&nilfs->ns_last_segment_lock);
583         sustat->ss_prot_seq = nilfs->ns_prot_seq;
584         spin_unlock(&nilfs->ns_last_segment_lock);
585         kunmap_atomic(kaddr, KM_USER0);
586         brelse(header_bh);
587
588  out_sem:
589         up_read(&NILFS_MDT(sufile)->mi_sem);
590         return ret;
591 }
592
593 void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
594                                struct buffer_head *header_bh,
595                                struct buffer_head *su_bh)
596 {
597         struct nilfs_segment_usage *su;
598         void *kaddr;
599         int suclean;
600
601         kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
602         su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
603         if (nilfs_segment_usage_error(su)) {
604                 kunmap_atomic(kaddr, KM_USER0);
605                 return;
606         }
607         suclean = nilfs_segment_usage_clean(su);
608         nilfs_segment_usage_set_error(su);
609         kunmap_atomic(kaddr, KM_USER0);
610
611         if (suclean) {
612                 nilfs_sufile_mod_counter(header_bh, -1, 0);
613                 NILFS_SUI(sufile)->ncleansegs--;
614         }
615         nilfs_mdt_mark_buffer_dirty(su_bh);
616         nilfs_mdt_mark_dirty(sufile);
617 }
618
619 /**
620   * nilfs_sufile_truncate_range - truncate range of segment array
621   * @sufile: inode of segment usage file
622   * @start: start segment number (inclusive)
623   * @end: end segment number (inclusive)
624   *
625   * Return Value: On success, 0 is returned.  On error, one of the
626   * following negative error codes is returned.
627   *
628   * %-EIO - I/O error.
629   *
630   * %-ENOMEM - Insufficient amount of memory available.
631   *
632   * %-EINVAL - Invalid number of segments specified
633   *
634   * %-EBUSY - Dirty or active segments are present in the range
635   */
636 static int nilfs_sufile_truncate_range(struct inode *sufile,
637                                        __u64 start, __u64 end)
638 {
639         struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
640         struct buffer_head *header_bh;
641         struct buffer_head *su_bh;
642         struct nilfs_segment_usage *su, *su2;
643         size_t susz = NILFS_MDT(sufile)->mi_entry_size;
644         unsigned long segusages_per_block;
645         unsigned long nsegs, ncleaned;
646         __u64 segnum;
647         void *kaddr;
648         ssize_t n, nc;
649         int ret;
650         int j;
651
652         nsegs = nilfs_sufile_get_nsegments(sufile);
653
654         ret = -EINVAL;
655         if (start > end || start >= nsegs)
656                 goto out;
657
658         ret = nilfs_sufile_get_header_block(sufile, &header_bh);
659         if (ret < 0)
660                 goto out;
661
662         segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
663         ncleaned = 0;
664
665         for (segnum = start; segnum <= end; segnum += n) {
666                 n = min_t(unsigned long,
667                           segusages_per_block -
668                                   nilfs_sufile_get_offset(sufile, segnum),
669                           end - segnum + 1);
670                 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
671                                                            &su_bh);
672                 if (ret < 0) {
673                         if (ret != -ENOENT)
674                                 goto out_header;
675                         /* hole */
676                         continue;
677                 }
678                 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
679                 su = nilfs_sufile_block_get_segment_usage(
680                         sufile, segnum, su_bh, kaddr);
681                 su2 = su;
682                 for (j = 0; j < n; j++, su = (void *)su + susz) {
683                         if ((le32_to_cpu(su->su_flags) &
684                              ~(1UL << NILFS_SEGMENT_USAGE_ERROR)) ||
685                             nilfs_segment_is_active(nilfs, segnum + j)) {
686                                 ret = -EBUSY;
687                                 kunmap_atomic(kaddr, KM_USER0);
688                                 brelse(su_bh);
689                                 goto out_header;
690                         }
691                 }
692                 nc = 0;
693                 for (su = su2, j = 0; j < n; j++, su = (void *)su + susz) {
694                         if (nilfs_segment_usage_error(su)) {
695                                 nilfs_segment_usage_set_clean(su);
696                                 nc++;
697                         }
698                 }
699                 kunmap_atomic(kaddr, KM_USER0);
700                 if (nc > 0) {
701                         nilfs_mdt_mark_buffer_dirty(su_bh);
702                         ncleaned += nc;
703                 }
704                 brelse(su_bh);
705
706                 if (n == segusages_per_block) {
707                         /* make hole */
708                         nilfs_sufile_delete_segment_usage_block(sufile, segnum);
709                 }
710         }
711         ret = 0;
712
713 out_header:
714         if (ncleaned > 0) {
715                 NILFS_SUI(sufile)->ncleansegs += ncleaned;
716                 nilfs_sufile_mod_counter(header_bh, ncleaned, 0);
717                 nilfs_mdt_mark_dirty(sufile);
718         }
719         brelse(header_bh);
720 out:
721         return ret;
722 }
723
724 /**
725  * nilfs_sufile_get_suinfo -
726  * @sufile: inode of segment usage file
727  * @segnum: segment number to start looking
728  * @buf: array of suinfo
729  * @sisz: byte size of suinfo
730  * @nsi: size of suinfo array
731  *
732  * Description:
733  *
734  * Return Value: On success, 0 is returned and .... On error, one of the
735  * following negative error codes is returned.
736  *
737  * %-EIO - I/O error.
738  *
739  * %-ENOMEM - Insufficient amount of memory available.
740  */
741 ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
742                                 unsigned sisz, size_t nsi)
743 {
744         struct buffer_head *su_bh;
745         struct nilfs_segment_usage *su;
746         struct nilfs_suinfo *si = buf;
747         size_t susz = NILFS_MDT(sufile)->mi_entry_size;
748         struct the_nilfs *nilfs = NILFS_I_NILFS(sufile);
749         void *kaddr;
750         unsigned long nsegs, segusages_per_block;
751         ssize_t n;
752         int ret, i, j;
753
754         down_read(&NILFS_MDT(sufile)->mi_sem);
755
756         segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
757         nsegs = min_t(unsigned long,
758                       nilfs_sufile_get_nsegments(sufile) - segnum,
759                       nsi);
760         for (i = 0; i < nsegs; i += n, segnum += n) {
761                 n = min_t(unsigned long,
762                           segusages_per_block -
763                                   nilfs_sufile_get_offset(sufile, segnum),
764                           nsegs - i);
765                 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
766                                                            &su_bh);
767                 if (ret < 0) {
768                         if (ret != -ENOENT)
769                                 goto out;
770                         /* hole */
771                         memset(si, 0, sisz * n);
772                         si = (void *)si + sisz * n;
773                         continue;
774                 }
775
776                 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
777                 su = nilfs_sufile_block_get_segment_usage(
778                         sufile, segnum, su_bh, kaddr);
779                 for (j = 0; j < n;
780                      j++, su = (void *)su + susz, si = (void *)si + sisz) {
781                         si->sui_lastmod = le64_to_cpu(su->su_lastmod);
782                         si->sui_nblocks = le32_to_cpu(su->su_nblocks);
783                         si->sui_flags = le32_to_cpu(su->su_flags) &
784                                 ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
785                         if (nilfs_segment_is_active(nilfs, segnum + j))
786                                 si->sui_flags |=
787                                         (1UL << NILFS_SEGMENT_USAGE_ACTIVE);
788                 }
789                 kunmap_atomic(kaddr, KM_USER0);
790                 brelse(su_bh);
791         }
792         ret = nsegs;
793
794  out:
795         up_read(&NILFS_MDT(sufile)->mi_sem);
796         return ret;
797 }
798
799 /**
800  * nilfs_sufile_read - read or get sufile inode
801  * @sb: super block instance
802  * @susize: size of a segment usage entry
803  * @raw_inode: on-disk sufile inode
804  * @inodep: buffer to store the inode
805  */
806 int nilfs_sufile_read(struct super_block *sb, size_t susize,
807                       struct nilfs_inode *raw_inode, struct inode **inodep)
808 {
809         struct inode *sufile;
810         struct nilfs_sufile_info *sui;
811         struct buffer_head *header_bh;
812         struct nilfs_sufile_header *header;
813         void *kaddr;
814         int err;
815
816         sufile = nilfs_iget_locked(sb, NULL, NILFS_SUFILE_INO);
817         if (unlikely(!sufile))
818                 return -ENOMEM;
819         if (!(sufile->i_state & I_NEW))
820                 goto out;
821
822         err = nilfs_mdt_init(sufile, NILFS_MDT_GFP, sizeof(*sui));
823         if (err)
824                 goto failed;
825
826         nilfs_mdt_set_entry_size(sufile, susize,
827                                  sizeof(struct nilfs_sufile_header));
828
829         err = nilfs_read_inode_common(sufile, raw_inode);
830         if (err)
831                 goto failed;
832
833         err = nilfs_sufile_get_header_block(sufile, &header_bh);
834         if (err)
835                 goto failed;
836
837         sui = NILFS_SUI(sufile);
838         kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
839         header = kaddr + bh_offset(header_bh);
840         sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs);
841         kunmap_atomic(kaddr, KM_USER0);
842         brelse(header_bh);
843
844         sui->allocmax = nilfs_sufile_get_nsegments(sufile) - 1;
845         sui->allocmin = 0;
846
847         unlock_new_inode(sufile);
848  out:
849         *inodep = sufile;
850         return 0;
851  failed:
852         iget_failed(sufile);
853         return err;
854 }