1
2
3
4
5
6
7
8
9
10
11#include <linux/kernel.h>
12#include <linux/fs.h>
13#include <linux/string.h>
14#include <linux/buffer_head.h>
15#include <linux/errno.h>
16#include "mdt.h"
17#include "sufile.h"
18
19#include <trace/events/nilfs2.h>
20
21
22
23
24
25
26
27
28struct nilfs_sufile_info {
29 struct nilfs_mdt_info mi;
30 unsigned long ncleansegs;
31 __u64 allocmin;
32 __u64 allocmax;
33};
34
35static inline struct nilfs_sufile_info *NILFS_SUI(struct inode *sufile)
36{
37 return (struct nilfs_sufile_info *)NILFS_MDT(sufile);
38}
39
40static inline unsigned long
41nilfs_sufile_segment_usages_per_block(const struct inode *sufile)
42{
43 return NILFS_MDT(sufile)->mi_entries_per_block;
44}
45
46static unsigned long
47nilfs_sufile_get_blkoff(const struct inode *sufile, __u64 segnum)
48{
49 __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset;
50
51 do_div(t, nilfs_sufile_segment_usages_per_block(sufile));
52 return (unsigned long)t;
53}
54
55static unsigned long
56nilfs_sufile_get_offset(const struct inode *sufile, __u64 segnum)
57{
58 __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset;
59
60 return do_div(t, nilfs_sufile_segment_usages_per_block(sufile));
61}
62
63static unsigned long
64nilfs_sufile_segment_usages_in_block(const struct inode *sufile, __u64 curr,
65 __u64 max)
66{
67 return min_t(unsigned long,
68 nilfs_sufile_segment_usages_per_block(sufile) -
69 nilfs_sufile_get_offset(sufile, curr),
70 max - curr + 1);
71}
72
73static struct nilfs_segment_usage *
74nilfs_sufile_block_get_segment_usage(const struct inode *sufile, __u64 segnum,
75 struct buffer_head *bh, void *kaddr)
76{
77 return kaddr + bh_offset(bh) +
78 nilfs_sufile_get_offset(sufile, segnum) *
79 NILFS_MDT(sufile)->mi_entry_size;
80}
81
82static inline int nilfs_sufile_get_header_block(struct inode *sufile,
83 struct buffer_head **bhp)
84{
85 return nilfs_mdt_get_block(sufile, 0, 0, NULL, bhp);
86}
87
88static inline int
89nilfs_sufile_get_segment_usage_block(struct inode *sufile, __u64 segnum,
90 int create, struct buffer_head **bhp)
91{
92 return nilfs_mdt_get_block(sufile,
93 nilfs_sufile_get_blkoff(sufile, segnum),
94 create, NULL, bhp);
95}
96
97static int nilfs_sufile_delete_segment_usage_block(struct inode *sufile,
98 __u64 segnum)
99{
100 return nilfs_mdt_delete_block(sufile,
101 nilfs_sufile_get_blkoff(sufile, segnum));
102}
103
104static void nilfs_sufile_mod_counter(struct buffer_head *header_bh,
105 u64 ncleanadd, u64 ndirtyadd)
106{
107 struct nilfs_sufile_header *header;
108 void *kaddr;
109
110 kaddr = kmap_atomic(header_bh->b_page);
111 header = kaddr + bh_offset(header_bh);
112 le64_add_cpu(&header->sh_ncleansegs, ncleanadd);
113 le64_add_cpu(&header->sh_ndirtysegs, ndirtyadd);
114 kunmap_atomic(kaddr);
115
116 mark_buffer_dirty(header_bh);
117}
118
119
120
121
122
123unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile)
124{
125 return NILFS_SUI(sufile)->ncleansegs;
126}
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
157 int create, size_t *ndone,
158 void (*dofunc)(struct inode *, __u64,
159 struct buffer_head *,
160 struct buffer_head *))
161{
162 struct buffer_head *header_bh, *bh;
163 unsigned long blkoff, prev_blkoff;
164 __u64 *seg;
165 size_t nerr = 0, n = 0;
166 int ret = 0;
167
168 if (unlikely(nsegs == 0))
169 goto out;
170
171 down_write(&NILFS_MDT(sufile)->mi_sem);
172 for (seg = segnumv; seg < segnumv + nsegs; seg++) {
173 if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
174 nilfs_msg(sufile->i_sb, KERN_WARNING,
175 "%s: invalid segment number: %llu",
176 __func__, (unsigned long long)*seg);
177 nerr++;
178 }
179 }
180 if (nerr > 0) {
181 ret = -EINVAL;
182 goto out_sem;
183 }
184
185 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
186 if (ret < 0)
187 goto out_sem;
188
189 seg = segnumv;
190 blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
191 ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
192 if (ret < 0)
193 goto out_header;
194
195 for (;;) {
196 dofunc(sufile, *seg, header_bh, bh);
197
198 if (++seg >= segnumv + nsegs)
199 break;
200 prev_blkoff = blkoff;
201 blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
202 if (blkoff == prev_blkoff)
203 continue;
204
205
206 brelse(bh);
207 ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
208 if (unlikely(ret < 0))
209 goto out_header;
210 }
211 brelse(bh);
212
213 out_header:
214 n = seg - segnumv;
215 brelse(header_bh);
216 out_sem:
217 up_write(&NILFS_MDT(sufile)->mi_sem);
218 out:
219 if (ndone)
220 *ndone = n;
221 return ret;
222}
223
224int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
225 void (*dofunc)(struct inode *, __u64,
226 struct buffer_head *,
227 struct buffer_head *))
228{
229 struct buffer_head *header_bh, *bh;
230 int ret;
231
232 if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) {
233 nilfs_msg(sufile->i_sb, KERN_WARNING,
234 "%s: invalid segment number: %llu",
235 __func__, (unsigned long long)segnum);
236 return -EINVAL;
237 }
238 down_write(&NILFS_MDT(sufile)->mi_sem);
239
240 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
241 if (ret < 0)
242 goto out_sem;
243
244 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, create, &bh);
245 if (!ret) {
246 dofunc(sufile, segnum, header_bh, bh);
247 brelse(bh);
248 }
249 brelse(header_bh);
250
251 out_sem:
252 up_write(&NILFS_MDT(sufile)->mi_sem);
253 return ret;
254}
255
256
257
258
259
260
261
262
263
264
265
266
267int nilfs_sufile_set_alloc_range(struct inode *sufile, __u64 start, __u64 end)
268{
269 struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
270 __u64 nsegs;
271 int ret = -ERANGE;
272
273 down_write(&NILFS_MDT(sufile)->mi_sem);
274 nsegs = nilfs_sufile_get_nsegments(sufile);
275
276 if (start <= end && end < nsegs) {
277 sui->allocmin = start;
278 sui->allocmax = end;
279 ret = 0;
280 }
281 up_write(&NILFS_MDT(sufile)->mi_sem);
282 return ret;
283}
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump)
303{
304 struct buffer_head *header_bh, *su_bh;
305 struct nilfs_sufile_header *header;
306 struct nilfs_segment_usage *su;
307 struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
308 size_t susz = NILFS_MDT(sufile)->mi_entry_size;
309 __u64 segnum, maxsegnum, last_alloc;
310 void *kaddr;
311 unsigned long nsegments, nsus, cnt;
312 int ret, j;
313
314 down_write(&NILFS_MDT(sufile)->mi_sem);
315
316 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
317 if (ret < 0)
318 goto out_sem;
319 kaddr = kmap_atomic(header_bh->b_page);
320 header = kaddr + bh_offset(header_bh);
321 last_alloc = le64_to_cpu(header->sh_last_alloc);
322 kunmap_atomic(kaddr);
323
324 nsegments = nilfs_sufile_get_nsegments(sufile);
325 maxsegnum = sui->allocmax;
326 segnum = last_alloc + 1;
327 if (segnum < sui->allocmin || segnum > sui->allocmax)
328 segnum = sui->allocmin;
329
330 for (cnt = 0; cnt < nsegments; cnt += nsus) {
331 if (segnum > maxsegnum) {
332 if (cnt < sui->allocmax - sui->allocmin + 1) {
333
334
335
336
337
338 segnum = sui->allocmin;
339 maxsegnum = last_alloc;
340 } else if (segnum > sui->allocmin &&
341 sui->allocmax + 1 < nsegments) {
342 segnum = sui->allocmax + 1;
343 maxsegnum = nsegments - 1;
344 } else if (sui->allocmin > 0) {
345 segnum = 0;
346 maxsegnum = sui->allocmin - 1;
347 } else {
348 break;
349 }
350 }
351 trace_nilfs2_segment_usage_check(sufile, segnum, cnt);
352 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1,
353 &su_bh);
354 if (ret < 0)
355 goto out_header;
356 kaddr = kmap_atomic(su_bh->b_page);
357 su = nilfs_sufile_block_get_segment_usage(
358 sufile, segnum, su_bh, kaddr);
359
360 nsus = nilfs_sufile_segment_usages_in_block(
361 sufile, segnum, maxsegnum);
362 for (j = 0; j < nsus; j++, su = (void *)su + susz, segnum++) {
363 if (!nilfs_segment_usage_clean(su))
364 continue;
365
366 nilfs_segment_usage_set_dirty(su);
367 kunmap_atomic(kaddr);
368
369 kaddr = kmap_atomic(header_bh->b_page);
370 header = kaddr + bh_offset(header_bh);
371 le64_add_cpu(&header->sh_ncleansegs, -1);
372 le64_add_cpu(&header->sh_ndirtysegs, 1);
373 header->sh_last_alloc = cpu_to_le64(segnum);
374 kunmap_atomic(kaddr);
375
376 sui->ncleansegs--;
377 mark_buffer_dirty(header_bh);
378 mark_buffer_dirty(su_bh);
379 nilfs_mdt_mark_dirty(sufile);
380 brelse(su_bh);
381 *segnump = segnum;
382
383 trace_nilfs2_segment_usage_allocated(sufile, segnum);
384
385 goto out_header;
386 }
387
388 kunmap_atomic(kaddr);
389 brelse(su_bh);
390 }
391
392
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
403void 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);
411 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
412 if (unlikely(!nilfs_segment_usage_clean(su))) {
413 nilfs_msg(sufile->i_sb, KERN_WARNING,
414 "%s: segment %llu must be clean", __func__,
415 (unsigned long long)segnum);
416 kunmap_atomic(kaddr);
417 return;
418 }
419 nilfs_segment_usage_set_dirty(su);
420 kunmap_atomic(kaddr);
421
422 nilfs_sufile_mod_counter(header_bh, -1, 1);
423 NILFS_SUI(sufile)->ncleansegs--;
424
425 mark_buffer_dirty(su_bh);
426 nilfs_mdt_mark_dirty(sufile);
427}
428
429void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
430 struct buffer_head *header_bh,
431 struct buffer_head *su_bh)
432{
433 struct nilfs_segment_usage *su;
434 void *kaddr;
435 int clean, dirty;
436
437 kaddr = kmap_atomic(su_bh->b_page);
438 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
439 if (su->su_flags == cpu_to_le32(BIT(NILFS_SEGMENT_USAGE_DIRTY)) &&
440 su->su_nblocks == cpu_to_le32(0)) {
441 kunmap_atomic(kaddr);
442 return;
443 }
444 clean = nilfs_segment_usage_clean(su);
445 dirty = nilfs_segment_usage_dirty(su);
446
447
448 su->su_lastmod = cpu_to_le64(0);
449 su->su_nblocks = cpu_to_le32(0);
450 su->su_flags = cpu_to_le32(BIT(NILFS_SEGMENT_USAGE_DIRTY));
451 kunmap_atomic(kaddr);
452
453 nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1);
454 NILFS_SUI(sufile)->ncleansegs -= clean;
455
456 mark_buffer_dirty(su_bh);
457 nilfs_mdt_mark_dirty(sufile);
458}
459
460void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
461 struct buffer_head *header_bh,
462 struct buffer_head *su_bh)
463{
464 struct nilfs_segment_usage *su;
465 void *kaddr;
466 int sudirty;
467
468 kaddr = kmap_atomic(su_bh->b_page);
469 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
470 if (nilfs_segment_usage_clean(su)) {
471 nilfs_msg(sufile->i_sb, KERN_WARNING,
472 "%s: segment %llu is already clean",
473 __func__, (unsigned long long)segnum);
474 kunmap_atomic(kaddr);
475 return;
476 }
477 WARN_ON(nilfs_segment_usage_error(su));
478 WARN_ON(!nilfs_segment_usage_dirty(su));
479
480 sudirty = nilfs_segment_usage_dirty(su);
481 nilfs_segment_usage_set_clean(su);
482 kunmap_atomic(kaddr);
483 mark_buffer_dirty(su_bh);
484
485 nilfs_sufile_mod_counter(header_bh, 1, sudirty ? (u64)-1 : 0);
486 NILFS_SUI(sufile)->ncleansegs++;
487
488 nilfs_mdt_mark_dirty(sufile);
489
490 trace_nilfs2_segment_usage_freed(sufile, segnum);
491}
492
493
494
495
496
497
498int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum)
499{
500 struct buffer_head *bh;
501 int ret;
502
503 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
504 if (!ret) {
505 mark_buffer_dirty(bh);
506 nilfs_mdt_mark_dirty(sufile);
507 brelse(bh);
508 }
509 return ret;
510}
511
512
513
514
515
516
517
518
519int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
520 unsigned long nblocks, time64_t modtime)
521{
522 struct buffer_head *bh;
523 struct nilfs_segment_usage *su;
524 void *kaddr;
525 int ret;
526
527 down_write(&NILFS_MDT(sufile)->mi_sem);
528 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
529 if (ret < 0)
530 goto out_sem;
531
532 kaddr = kmap_atomic(bh->b_page);
533 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
534 WARN_ON(nilfs_segment_usage_error(su));
535 if (modtime)
536 su->su_lastmod = cpu_to_le64(modtime);
537 su->su_nblocks = cpu_to_le32(nblocks);
538 kunmap_atomic(kaddr);
539
540 mark_buffer_dirty(bh);
541 nilfs_mdt_mark_dirty(sufile);
542 brelse(bh);
543
544 out_sem:
545 up_write(&NILFS_MDT(sufile)->mi_sem);
546 return ret;
547}
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat)
566{
567 struct buffer_head *header_bh;
568 struct nilfs_sufile_header *header;
569 struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
570 void *kaddr;
571 int ret;
572
573 down_read(&NILFS_MDT(sufile)->mi_sem);
574
575 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
576 if (ret < 0)
577 goto out_sem;
578
579 kaddr = kmap_atomic(header_bh->b_page);
580 header = kaddr + bh_offset(header_bh);
581 sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile);
582 sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs);
583 sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs);
584 sustat->ss_ctime = nilfs->ns_ctime;
585 sustat->ss_nongc_ctime = nilfs->ns_nongc_ctime;
586 spin_lock(&nilfs->ns_last_segment_lock);
587 sustat->ss_prot_seq = nilfs->ns_prot_seq;
588 spin_unlock(&nilfs->ns_last_segment_lock);
589 kunmap_atomic(kaddr);
590 brelse(header_bh);
591
592 out_sem:
593 up_read(&NILFS_MDT(sufile)->mi_sem);
594 return ret;
595}
596
597void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
598 struct buffer_head *header_bh,
599 struct buffer_head *su_bh)
600{
601 struct nilfs_segment_usage *su;
602 void *kaddr;
603 int suclean;
604
605 kaddr = kmap_atomic(su_bh->b_page);
606 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
607 if (nilfs_segment_usage_error(su)) {
608 kunmap_atomic(kaddr);
609 return;
610 }
611 suclean = nilfs_segment_usage_clean(su);
612 nilfs_segment_usage_set_error(su);
613 kunmap_atomic(kaddr);
614
615 if (suclean) {
616 nilfs_sufile_mod_counter(header_bh, -1, 0);
617 NILFS_SUI(sufile)->ncleansegs--;
618 }
619 mark_buffer_dirty(su_bh);
620 nilfs_mdt_mark_dirty(sufile);
621}
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640static int nilfs_sufile_truncate_range(struct inode *sufile,
641 __u64 start, __u64 end)
642{
643 struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
644 struct buffer_head *header_bh;
645 struct buffer_head *su_bh;
646 struct nilfs_segment_usage *su, *su2;
647 size_t susz = NILFS_MDT(sufile)->mi_entry_size;
648 unsigned long segusages_per_block;
649 unsigned long nsegs, ncleaned;
650 __u64 segnum;
651 void *kaddr;
652 ssize_t n, nc;
653 int ret;
654 int j;
655
656 nsegs = nilfs_sufile_get_nsegments(sufile);
657
658 ret = -EINVAL;
659 if (start > end || start >= nsegs)
660 goto out;
661
662 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
663 if (ret < 0)
664 goto out;
665
666 segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
667 ncleaned = 0;
668
669 for (segnum = start; segnum <= end; segnum += n) {
670 n = min_t(unsigned long,
671 segusages_per_block -
672 nilfs_sufile_get_offset(sufile, segnum),
673 end - segnum + 1);
674 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
675 &su_bh);
676 if (ret < 0) {
677 if (ret != -ENOENT)
678 goto out_header;
679
680 continue;
681 }
682 kaddr = kmap_atomic(su_bh->b_page);
683 su = nilfs_sufile_block_get_segment_usage(
684 sufile, segnum, su_bh, kaddr);
685 su2 = su;
686 for (j = 0; j < n; j++, su = (void *)su + susz) {
687 if ((le32_to_cpu(su->su_flags) &
688 ~BIT(NILFS_SEGMENT_USAGE_ERROR)) ||
689 nilfs_segment_is_active(nilfs, segnum + j)) {
690 ret = -EBUSY;
691 kunmap_atomic(kaddr);
692 brelse(su_bh);
693 goto out_header;
694 }
695 }
696 nc = 0;
697 for (su = su2, j = 0; j < n; j++, su = (void *)su + susz) {
698 if (nilfs_segment_usage_error(su)) {
699 nilfs_segment_usage_set_clean(su);
700 nc++;
701 }
702 }
703 kunmap_atomic(kaddr);
704 if (nc > 0) {
705 mark_buffer_dirty(su_bh);
706 ncleaned += nc;
707 }
708 brelse(su_bh);
709
710 if (n == segusages_per_block) {
711
712 nilfs_sufile_delete_segment_usage_block(sufile, segnum);
713 }
714 }
715 ret = 0;
716
717out_header:
718 if (ncleaned > 0) {
719 NILFS_SUI(sufile)->ncleansegs += ncleaned;
720 nilfs_sufile_mod_counter(header_bh, ncleaned, 0);
721 nilfs_mdt_mark_dirty(sufile);
722 }
723 brelse(header_bh);
724out:
725 return ret;
726}
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744int nilfs_sufile_resize(struct inode *sufile, __u64 newnsegs)
745{
746 struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
747 struct buffer_head *header_bh;
748 struct nilfs_sufile_header *header;
749 struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
750 void *kaddr;
751 unsigned long nsegs, nrsvsegs;
752 int ret = 0;
753
754 down_write(&NILFS_MDT(sufile)->mi_sem);
755
756 nsegs = nilfs_sufile_get_nsegments(sufile);
757 if (nsegs == newnsegs)
758 goto out;
759
760 ret = -ENOSPC;
761 nrsvsegs = nilfs_nrsvsegs(nilfs, newnsegs);
762 if (newnsegs < nsegs && nsegs - newnsegs + nrsvsegs > sui->ncleansegs)
763 goto out;
764
765 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
766 if (ret < 0)
767 goto out;
768
769 if (newnsegs > nsegs) {
770 sui->ncleansegs += newnsegs - nsegs;
771 } else {
772 ret = nilfs_sufile_truncate_range(sufile, newnsegs, nsegs - 1);
773 if (ret < 0)
774 goto out_header;
775
776 sui->ncleansegs -= nsegs - newnsegs;
777 }
778
779 kaddr = kmap_atomic(header_bh->b_page);
780 header = kaddr + bh_offset(header_bh);
781 header->sh_ncleansegs = cpu_to_le64(sui->ncleansegs);
782 kunmap_atomic(kaddr);
783
784 mark_buffer_dirty(header_bh);
785 nilfs_mdt_mark_dirty(sufile);
786 nilfs_set_nsegments(nilfs, newnsegs);
787
788out_header:
789 brelse(header_bh);
790out:
791 up_write(&NILFS_MDT(sufile)->mi_sem);
792 return ret;
793}
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
813 unsigned int sisz, size_t nsi)
814{
815 struct buffer_head *su_bh;
816 struct nilfs_segment_usage *su;
817 struct nilfs_suinfo *si = buf;
818 size_t susz = NILFS_MDT(sufile)->mi_entry_size;
819 struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
820 void *kaddr;
821 unsigned long nsegs, segusages_per_block;
822 ssize_t n;
823 int ret, i, j;
824
825 down_read(&NILFS_MDT(sufile)->mi_sem);
826
827 segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
828 nsegs = min_t(unsigned long,
829 nilfs_sufile_get_nsegments(sufile) - segnum,
830 nsi);
831 for (i = 0; i < nsegs; i += n, segnum += n) {
832 n = min_t(unsigned long,
833 segusages_per_block -
834 nilfs_sufile_get_offset(sufile, segnum),
835 nsegs - i);
836 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
837 &su_bh);
838 if (ret < 0) {
839 if (ret != -ENOENT)
840 goto out;
841
842 memset(si, 0, sisz * n);
843 si = (void *)si + sisz * n;
844 continue;
845 }
846
847 kaddr = kmap_atomic(su_bh->b_page);
848 su = nilfs_sufile_block_get_segment_usage(
849 sufile, segnum, su_bh, kaddr);
850 for (j = 0; j < n;
851 j++, su = (void *)su + susz, si = (void *)si + sisz) {
852 si->sui_lastmod = le64_to_cpu(su->su_lastmod);
853 si->sui_nblocks = le32_to_cpu(su->su_nblocks);
854 si->sui_flags = le32_to_cpu(su->su_flags) &
855 ~BIT(NILFS_SEGMENT_USAGE_ACTIVE);
856 if (nilfs_segment_is_active(nilfs, segnum + j))
857 si->sui_flags |=
858 BIT(NILFS_SEGMENT_USAGE_ACTIVE);
859 }
860 kunmap_atomic(kaddr);
861 brelse(su_bh);
862 }
863 ret = nsegs;
864
865 out:
866 up_read(&NILFS_MDT(sufile)->mi_sem);
867 return ret;
868}
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
891 unsigned int supsz, size_t nsup)
892{
893 struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
894 struct buffer_head *header_bh, *bh;
895 struct nilfs_suinfo_update *sup, *supend = buf + supsz * nsup;
896 struct nilfs_segment_usage *su;
897 void *kaddr;
898 unsigned long blkoff, prev_blkoff;
899 int cleansi, cleansu, dirtysi, dirtysu;
900 long ncleaned = 0, ndirtied = 0;
901 int ret = 0;
902
903 if (unlikely(nsup == 0))
904 return ret;
905
906 for (sup = buf; sup < supend; sup = (void *)sup + supsz) {
907 if (sup->sup_segnum >= nilfs->ns_nsegments
908 || (sup->sup_flags &
909 (~0UL << __NR_NILFS_SUINFO_UPDATE_FIELDS))
910 || (nilfs_suinfo_update_nblocks(sup) &&
911 sup->sup_sui.sui_nblocks >
912 nilfs->ns_blocks_per_segment))
913 return -EINVAL;
914 }
915
916 down_write(&NILFS_MDT(sufile)->mi_sem);
917
918 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
919 if (ret < 0)
920 goto out_sem;
921
922 sup = buf;
923 blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
924 ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
925 if (ret < 0)
926 goto out_header;
927
928 for (;;) {
929 kaddr = kmap_atomic(bh->b_page);
930 su = nilfs_sufile_block_get_segment_usage(
931 sufile, sup->sup_segnum, bh, kaddr);
932
933 if (nilfs_suinfo_update_lastmod(sup))
934 su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
935
936 if (nilfs_suinfo_update_nblocks(sup))
937 su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
938
939 if (nilfs_suinfo_update_flags(sup)) {
940
941
942
943
944
945 sup->sup_sui.sui_flags &=
946 ~BIT(NILFS_SEGMENT_USAGE_ACTIVE);
947
948 cleansi = nilfs_suinfo_clean(&sup->sup_sui);
949 cleansu = nilfs_segment_usage_clean(su);
950 dirtysi = nilfs_suinfo_dirty(&sup->sup_sui);
951 dirtysu = nilfs_segment_usage_dirty(su);
952
953 if (cleansi && !cleansu)
954 ++ncleaned;
955 else if (!cleansi && cleansu)
956 --ncleaned;
957
958 if (dirtysi && !dirtysu)
959 ++ndirtied;
960 else if (!dirtysi && dirtysu)
961 --ndirtied;
962
963 su->su_flags = cpu_to_le32(sup->sup_sui.sui_flags);
964 }
965
966 kunmap_atomic(kaddr);
967
968 sup = (void *)sup + supsz;
969 if (sup >= supend)
970 break;
971
972 prev_blkoff = blkoff;
973 blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
974 if (blkoff == prev_blkoff)
975 continue;
976
977
978 mark_buffer_dirty(bh);
979 put_bh(bh);
980 ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
981 if (unlikely(ret < 0))
982 goto out_mark;
983 }
984 mark_buffer_dirty(bh);
985 put_bh(bh);
986
987 out_mark:
988 if (ncleaned || ndirtied) {
989 nilfs_sufile_mod_counter(header_bh, (u64)ncleaned,
990 (u64)ndirtied);
991 NILFS_SUI(sufile)->ncleansegs += ncleaned;
992 }
993 nilfs_mdt_mark_dirty(sufile);
994 out_header:
995 put_bh(header_bh);
996 out_sem:
997 up_write(&NILFS_MDT(sufile)->mi_sem);
998 return ret;
999}
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017int nilfs_sufile_trim_fs(struct inode *sufile, struct fstrim_range *range)
1018{
1019 struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
1020 struct buffer_head *su_bh;
1021 struct nilfs_segment_usage *su;
1022 void *kaddr;
1023 size_t n, i, susz = NILFS_MDT(sufile)->mi_entry_size;
1024 sector_t seg_start, seg_end, start_block, end_block;
1025 sector_t start = 0, nblocks = 0;
1026 u64 segnum, segnum_end, minlen, len, max_blocks, ndiscarded = 0;
1027 int ret = 0;
1028 unsigned int sects_per_block;
1029
1030 sects_per_block = (1 << nilfs->ns_blocksize_bits) /
1031 bdev_logical_block_size(nilfs->ns_bdev);
1032 len = range->len >> nilfs->ns_blocksize_bits;
1033 minlen = range->minlen >> nilfs->ns_blocksize_bits;
1034 max_blocks = ((u64)nilfs->ns_nsegments * nilfs->ns_blocks_per_segment);
1035
1036 if (!len || range->start >= max_blocks << nilfs->ns_blocksize_bits)
1037 return -EINVAL;
1038
1039 start_block = (range->start + nilfs->ns_blocksize - 1) >>
1040 nilfs->ns_blocksize_bits;
1041
1042
1043
1044
1045
1046
1047 if (max_blocks - start_block < len)
1048 end_block = max_blocks - 1;
1049 else
1050 end_block = start_block + len - 1;
1051
1052 segnum = nilfs_get_segnum_of_block(nilfs, start_block);
1053 segnum_end = nilfs_get_segnum_of_block(nilfs, end_block);
1054
1055 down_read(&NILFS_MDT(sufile)->mi_sem);
1056
1057 while (segnum <= segnum_end) {
1058 n = nilfs_sufile_segment_usages_in_block(sufile, segnum,
1059 segnum_end);
1060
1061 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
1062 &su_bh);
1063 if (ret < 0) {
1064 if (ret != -ENOENT)
1065 goto out_sem;
1066
1067 segnum += n;
1068 continue;
1069 }
1070
1071 kaddr = kmap_atomic(su_bh->b_page);
1072 su = nilfs_sufile_block_get_segment_usage(sufile, segnum,
1073 su_bh, kaddr);
1074 for (i = 0; i < n; ++i, ++segnum, su = (void *)su + susz) {
1075 if (!nilfs_segment_usage_clean(su))
1076 continue;
1077
1078 nilfs_get_segment_range(nilfs, segnum, &seg_start,
1079 &seg_end);
1080
1081 if (!nblocks) {
1082
1083 start = seg_start;
1084 nblocks = seg_end - seg_start + 1;
1085 continue;
1086 }
1087
1088 if (start + nblocks == seg_start) {
1089
1090 nblocks += seg_end - seg_start + 1;
1091 continue;
1092 }
1093
1094
1095 if (start < start_block) {
1096 nblocks -= start_block - start;
1097 start = start_block;
1098 }
1099
1100 if (nblocks >= minlen) {
1101 kunmap_atomic(kaddr);
1102
1103 ret = blkdev_issue_discard(nilfs->ns_bdev,
1104 start * sects_per_block,
1105 nblocks * sects_per_block,
1106 GFP_NOFS, 0);
1107 if (ret < 0) {
1108 put_bh(su_bh);
1109 goto out_sem;
1110 }
1111
1112 ndiscarded += nblocks;
1113 kaddr = kmap_atomic(su_bh->b_page);
1114 su = nilfs_sufile_block_get_segment_usage(
1115 sufile, segnum, su_bh, kaddr);
1116 }
1117
1118
1119 start = seg_start;
1120 nblocks = seg_end - seg_start + 1;
1121 }
1122 kunmap_atomic(kaddr);
1123 put_bh(su_bh);
1124 }
1125
1126
1127 if (nblocks) {
1128
1129 if (start < start_block) {
1130 nblocks -= start_block - start;
1131 start = start_block;
1132 }
1133 if (start + nblocks > end_block + 1)
1134 nblocks = end_block - start + 1;
1135
1136 if (nblocks >= minlen) {
1137 ret = blkdev_issue_discard(nilfs->ns_bdev,
1138 start * sects_per_block,
1139 nblocks * sects_per_block,
1140 GFP_NOFS, 0);
1141 if (!ret)
1142 ndiscarded += nblocks;
1143 }
1144 }
1145
1146out_sem:
1147 up_read(&NILFS_MDT(sufile)->mi_sem);
1148
1149 range->len = ndiscarded << nilfs->ns_blocksize_bits;
1150 return ret;
1151}
1152
1153
1154
1155
1156
1157
1158
1159
1160int nilfs_sufile_read(struct super_block *sb, size_t susize,
1161 struct nilfs_inode *raw_inode, struct inode **inodep)
1162{
1163 struct inode *sufile;
1164 struct nilfs_sufile_info *sui;
1165 struct buffer_head *header_bh;
1166 struct nilfs_sufile_header *header;
1167 void *kaddr;
1168 int err;
1169
1170 if (susize > sb->s_blocksize) {
1171 nilfs_msg(sb, KERN_ERR,
1172 "too large segment usage size: %zu bytes", susize);
1173 return -EINVAL;
1174 } else if (susize < NILFS_MIN_SEGMENT_USAGE_SIZE) {
1175 nilfs_msg(sb, KERN_ERR,
1176 "too small segment usage size: %zu bytes", susize);
1177 return -EINVAL;
1178 }
1179
1180 sufile = nilfs_iget_locked(sb, NULL, NILFS_SUFILE_INO);
1181 if (unlikely(!sufile))
1182 return -ENOMEM;
1183 if (!(sufile->i_state & I_NEW))
1184 goto out;
1185
1186 err = nilfs_mdt_init(sufile, NILFS_MDT_GFP, sizeof(*sui));
1187 if (err)
1188 goto failed;
1189
1190 nilfs_mdt_set_entry_size(sufile, susize,
1191 sizeof(struct nilfs_sufile_header));
1192
1193 err = nilfs_read_inode_common(sufile, raw_inode);
1194 if (err)
1195 goto failed;
1196
1197 err = nilfs_sufile_get_header_block(sufile, &header_bh);
1198 if (err)
1199 goto failed;
1200
1201 sui = NILFS_SUI(sufile);
1202 kaddr = kmap_atomic(header_bh->b_page);
1203 header = kaddr + bh_offset(header_bh);
1204 sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs);
1205 kunmap_atomic(kaddr);
1206 brelse(header_bh);
1207
1208 sui->allocmax = nilfs_sufile_get_nsegments(sufile) - 1;
1209 sui->allocmin = 0;
1210
1211 unlock_new_inode(sufile);
1212 out:
1213 *inodep = sufile;
1214 return 0;
1215 failed:
1216 iget_failed(sufile);
1217 return err;
1218}
1219