blob: e9b4cec0d3ef4d2f3d2bc5067f71d7ea3c333a93 [file] [log] [blame]
Koji Sato6c98cd42009-04-06 19:01:32 -07001/*
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>.
Ryusuke Konishidda54f42009-05-16 21:49:10 +090021 * Rivised by Ryusuke Konishi <ryusuke@osrg.net>.
Koji Sato6c98cd42009-04-06 19:01:32 -070022 */
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
Ryusuke Konishiaa474a22009-11-13 03:41:55 +090034struct 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
Koji Sato6c98cd42009-04-06 19:01:32 -070044static 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
Koji Sato6c98cd42009-04-06 19:01:32 -070075static 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
Ryusuke Konishia7030182009-04-05 18:24:11 +090099static 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
Ryusuke Konishidda54f42009-05-16 21:49:10 +0900114/**
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
Ryusuke Konishia7030182009-04-05 18:24:11 +0900210int 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
Koji Sato6c98cd42009-04-06 19:01:32 -0700241/**
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;
Koji Sato6c98cd42009-04-06 19:01:32 -0700261 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
Koji Sato6c98cd42009-04-06 19:01:32 -0700271 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);
Ryusuke Konishi7b16c8a2009-11-13 03:10:21 +0900275 header = kaddr + bh_offset(header_bh);
Koji Sato6c98cd42009-04-06 19:01:32 -0700276 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 */
Koji Sato6c98cd42009-04-06 19:01:32 -0700303 nilfs_segment_usage_set_dirty(su);
304 kunmap_atomic(kaddr, KM_USER0);
305
306 kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
Ryusuke Konishi7b16c8a2009-11-13 03:10:21 +0900307 header = kaddr + bh_offset(header_bh);
Koji Sato6c98cd42009-04-06 19:01:32 -0700308 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
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900313 NILFS_SUI(sufile)->ncleansegs--;
Koji Sato6c98cd42009-04-06 19:01:32 -0700314 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
Ryusuke Konishia7030182009-04-05 18:24:11 +0900337void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
338 struct buffer_head *header_bh,
339 struct buffer_head *su_bh)
Koji Sato6c98cd42009-04-06 19:01:32 -0700340{
Koji Sato6c98cd42009-04-06 19:01:32 -0700341 struct nilfs_segment_usage *su;
342 void *kaddr;
Koji Sato6c98cd42009-04-06 19:01:32 -0700343
344 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900345 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700346 if (unlikely(!nilfs_segment_usage_clean(su))) {
347 printk(KERN_WARNING "%s: segment %llu must be clean\n",
Koji Sato6c98cd42009-04-06 19:01:32 -0700348 __func__, (unsigned long long)segnum);
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700349 kunmap_atomic(kaddr, KM_USER0);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900350 return;
Koji Sato6c98cd42009-04-06 19:01:32 -0700351 }
352 nilfs_segment_usage_set_dirty(su);
353 kunmap_atomic(kaddr, KM_USER0);
354
Ryusuke Konishia7030182009-04-05 18:24:11 +0900355 nilfs_sufile_mod_counter(header_bh, -1, 1);
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900356 NILFS_SUI(sufile)->ncleansegs--;
357
Koji Sato6c98cd42009-04-06 19:01:32 -0700358 nilfs_mdt_mark_buffer_dirty(su_bh);
359 nilfs_mdt_mark_dirty(sufile);
Koji Sato6c98cd42009-04-06 19:01:32 -0700360}
361
Ryusuke Konishic85399c2009-04-05 18:30:58 +0900362void 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);
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900387 NILFS_SUI(sufile)->ncleansegs -= clean;
388
Ryusuke Konishic85399c2009-04-05 18:30:58 +0900389 nilfs_mdt_mark_buffer_dirty(su_bh);
390 nilfs_mdt_mark_dirty(sufile);
391}
392
Ryusuke Konishia7030182009-04-05 18:24:11 +0900393void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
394 struct buffer_head *header_bh,
395 struct buffer_head *su_bh)
Koji Sato6c98cd42009-04-06 19:01:32 -0700396{
Koji Sato6c98cd42009-04-06 19:01:32 -0700397 struct nilfs_segment_usage *su;
398 void *kaddr;
Ryusuke Konishia7030182009-04-05 18:24:11 +0900399 int sudirty;
Koji Sato6c98cd42009-04-06 19:01:32 -0700400
Ryusuke Konishia7030182009-04-05 18:24:11 +0900401 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);
Koji Sato6c98cd42009-04-06 19:01:32 -0700406 kunmap_atomic(kaddr, KM_USER0);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900407 return;
Koji Sato6c98cd42009-04-06 19:01:32 -0700408 }
Ryusuke Konishia7030182009-04-05 18:24:11 +0900409 WARN_ON(nilfs_segment_usage_error(su));
410 WARN_ON(!nilfs_segment_usage_dirty(su));
411
412 sudirty = nilfs_segment_usage_dirty(su);
413 nilfs_segment_usage_set_clean(su);
Koji Sato6c98cd42009-04-06 19:01:32 -0700414 kunmap_atomic(kaddr, KM_USER0);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900415 nilfs_mdt_mark_buffer_dirty(su_bh);
416
417 nilfs_sufile_mod_counter(header_bh, 1, sudirty ? (u64)-1 : 0);
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900418 NILFS_SUI(sufile)->ncleansegs++;
419
Koji Sato6c98cd42009-04-06 19:01:32 -0700420 nilfs_mdt_mark_dirty(sufile);
Koji Sato6c98cd42009-04-06 19:01:32 -0700421}
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 */
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700454 if (segnum >= nilfs_sufile_get_nsegments(sufile))
455 return -EINVAL;
Koji Sato6c98cd42009-04-06 19:01:32 -0700456 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;
Ryusuke Konishi2c2e52f2009-04-06 19:01:54 -0700515 struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
Koji Sato6c98cd42009-04-06 19:01:32 -0700516 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);
Ryusuke Konishi7b16c8a2009-11-13 03:10:21 +0900526 header = kaddr + bh_offset(header_bh);
Koji Sato6c98cd42009-04-06 19:01:32 -0700527 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);
Ryusuke Konishi2c2e52f2009-04-06 19:01:54 -0700530 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);
Koji Sato6c98cd42009-04-06 19:01:32 -0700535 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{
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900561 *nsegsp = NILFS_SUI(sufile)->ncleansegs;
562 return 0;
Koji Sato6c98cd42009-04-06 19:01:32 -0700563}
564
Ryusuke Konishia7030182009-04-05 18:24:11 +0900565void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
566 struct buffer_head *header_bh,
567 struct buffer_head *su_bh)
Koji Sato6c98cd42009-04-06 19:01:32 -0700568{
Koji Sato6c98cd42009-04-06 19:01:32 -0700569 struct nilfs_segment_usage *su;
Koji Sato6c98cd42009-04-06 19:01:32 -0700570 void *kaddr;
Ryusuke Konishia7030182009-04-05 18:24:11 +0900571 int suclean;
Koji Sato6c98cd42009-04-06 19:01:32 -0700572
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);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900577 return;
Koji Sato6c98cd42009-04-06 19:01:32 -0700578 }
Ryusuke Konishi88072fa2009-04-05 15:03:16 +0900579 suclean = nilfs_segment_usage_clean(su);
Koji Sato6c98cd42009-04-06 19:01:32 -0700580 nilfs_segment_usage_set_error(su);
581 kunmap_atomic(kaddr, KM_USER0);
Koji Sato6c98cd42009-04-06 19:01:32 -0700582
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900583 if (suclean) {
Ryusuke Konishia7030182009-04-05 18:24:11 +0900584 nilfs_sufile_mod_counter(header_bh, -1, 0);
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900585 NILFS_SUI(sufile)->ncleansegs--;
586 }
Koji Sato6c98cd42009-04-06 19:01:32 -0700587 nilfs_mdt_mark_buffer_dirty(su_bh);
588 nilfs_mdt_mark_dirty(sufile);
Koji Sato6c98cd42009-04-06 19:01:32 -0700589}
590
591/**
592 * nilfs_sufile_get_suinfo -
593 * @sufile: inode of segment usage file
594 * @segnum: segment number to start looking
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900595 * @buf: array of suinfo
596 * @sisz: byte size of suinfo
Koji Sato6c98cd42009-04-06 19:01:32 -0700597 * @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 */
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900608ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
609 unsigned sisz, size_t nsi)
Koji Sato6c98cd42009-04-06 19:01:32 -0700610{
611 struct buffer_head *su_bh;
612 struct nilfs_segment_usage *su;
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900613 struct nilfs_suinfo *si = buf;
Koji Sato6c98cd42009-04-06 19:01:32 -0700614 size_t susz = NILFS_MDT(sufile)->mi_entry_size;
Ryusuke Konishicece5522009-04-06 19:01:58 -0700615 struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs;
Koji Sato6c98cd42009-04-06 19:01:32 -0700616 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 */
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900638 memset(si, 0, sisz * n);
639 si = (void *)si + sisz * n;
Koji Sato6c98cd42009-04-06 19:01:32 -0700640 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);
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900646 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) &
Ryusuke Konishicece5522009-04-06 19:01:58 -0700651 ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
Ryusuke Konishi3efb55b2009-03-30 00:50:19 +0900652 if (nilfs_segment_is_active(nilfs, segnum + j))
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900653 si->sui_flags |=
Ryusuke Konishicece5522009-04-06 19:01:58 -0700654 (1UL << NILFS_SEGMENT_USAGE_ACTIVE);
Koji Sato6c98cd42009-04-06 19:01:32 -0700655 }
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}
Ryusuke Konishi79739562009-11-12 23:56:43 +0900665
666/**
Ryusuke Konishi8707df32009-11-13 01:36:56 +0900667 * 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{
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900673 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;
Ryusuke Konishi8707df32009-11-13 01:36:56 +0900692}
693
694/**
Ryusuke Konishi79739562009-11-12 23:56:43 +0900695 * 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
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900703 sufile = nilfs_mdt_new(nilfs, NULL, NILFS_SUFILE_INO,
704 sizeof(struct nilfs_sufile_info));
Ryusuke Konishi79739562009-11-12 23:56:43 +0900705 if (sufile)
706 nilfs_mdt_set_entry_size(sufile, susize,
707 sizeof(struct nilfs_sufile_header));
708 return sufile;
709}