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