blob: f4374df00ad585f5137d2189bd37fabf26b2d4c3 [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 Konishi7a650042010-03-14 03:32:40 +090021 * Revised 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;
Ryusuke Konishi619205d2011-05-05 01:23:57 +090036 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 */
Ryusuke Konishiaa474a22009-11-13 03:41:55 +090039};
40
41static inline struct nilfs_sufile_info *NILFS_SUI(struct inode *sufile)
42{
43 return (struct nilfs_sufile_info *)NILFS_MDT(sufile);
44}
45
Koji Sato6c98cd42009-04-06 19:01:32 -070046static inline unsigned long
47nilfs_sufile_segment_usages_per_block(const struct inode *sufile)
48{
49 return NILFS_MDT(sufile)->mi_entries_per_block;
50}
51
52static unsigned long
53nilfs_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
60static unsigned long
61nilfs_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
67static unsigned long
68nilfs_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
Koji Sato6c98cd42009-04-06 19:01:32 -070077static struct nilfs_segment_usage *
78nilfs_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
86static 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
92static inline int
93nilfs_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
Ryusuke Konishia7030182009-04-05 18:24:11 +0900101static void nilfs_sufile_mod_counter(struct buffer_head *header_bh,
102 u64 ncleanadd, u64 ndirtyadd)
103{
104 struct nilfs_sufile_header *header;
105 void *kaddr;
106
107 kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
108 header = kaddr + bh_offset(header_bh);
109 le64_add_cpu(&header->sh_ncleansegs, ncleanadd);
110 le64_add_cpu(&header->sh_ndirtysegs, ndirtyadd);
111 kunmap_atomic(kaddr, KM_USER0);
112
113 nilfs_mdt_mark_buffer_dirty(header_bh);
114}
115
Ryusuke Konishidda54f42009-05-16 21:49:10 +0900116/**
Ryusuke Konishief7d4752009-11-13 08:45:32 +0900117 * nilfs_sufile_get_ncleansegs - return the number of clean segments
118 * @sufile: inode of segment usage file
119 */
120unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile)
121{
122 return NILFS_SUI(sufile)->ncleansegs;
123}
124
125/**
Ryusuke Konishidda54f42009-05-16 21:49:10 +0900126 * nilfs_sufile_updatev - modify multiple segment usages at a time
127 * @sufile: inode of segment usage file
128 * @segnumv: array of segment numbers
129 * @nsegs: size of @segnumv array
130 * @create: creation flag
131 * @ndone: place to store number of modified segments on @segnumv
132 * @dofunc: primitive operation for the update
133 *
134 * Description: nilfs_sufile_updatev() repeatedly calls @dofunc
135 * against the given array of segments. The @dofunc is called with
136 * buffers of a header block and the sufile block in which the target
137 * segment usage entry is contained. If @ndone is given, the number
138 * of successfully modified segments from the head is stored in the
139 * place @ndone points to.
140 *
141 * Return Value: On success, zero is returned. On error, one of the
142 * following negative error codes is returned.
143 *
144 * %-EIO - I/O error.
145 *
146 * %-ENOMEM - Insufficient amount of memory available.
147 *
148 * %-ENOENT - Given segment usage is in hole block (may be returned if
149 * @create is zero)
150 *
151 * %-EINVAL - Invalid segment usage number
152 */
153int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
154 int create, size_t *ndone,
155 void (*dofunc)(struct inode *, __u64,
156 struct buffer_head *,
157 struct buffer_head *))
158{
159 struct buffer_head *header_bh, *bh;
160 unsigned long blkoff, prev_blkoff;
161 __u64 *seg;
162 size_t nerr = 0, n = 0;
163 int ret = 0;
164
165 if (unlikely(nsegs == 0))
166 goto out;
167
168 down_write(&NILFS_MDT(sufile)->mi_sem);
169 for (seg = segnumv; seg < segnumv + nsegs; seg++) {
170 if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
171 printk(KERN_WARNING
172 "%s: invalid segment number: %llu\n", __func__,
173 (unsigned long long)*seg);
174 nerr++;
175 }
176 }
177 if (nerr > 0) {
178 ret = -EINVAL;
179 goto out_sem;
180 }
181
182 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
183 if (ret < 0)
184 goto out_sem;
185
186 seg = segnumv;
187 blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
188 ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
189 if (ret < 0)
190 goto out_header;
191
192 for (;;) {
193 dofunc(sufile, *seg, header_bh, bh);
194
195 if (++seg >= segnumv + nsegs)
196 break;
197 prev_blkoff = blkoff;
198 blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
199 if (blkoff == prev_blkoff)
200 continue;
201
202 /* get different block */
203 brelse(bh);
204 ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
205 if (unlikely(ret < 0))
206 goto out_header;
207 }
208 brelse(bh);
209
210 out_header:
211 n = seg - segnumv;
212 brelse(header_bh);
213 out_sem:
214 up_write(&NILFS_MDT(sufile)->mi_sem);
215 out:
216 if (ndone)
217 *ndone = n;
218 return ret;
219}
220
Ryusuke Konishia7030182009-04-05 18:24:11 +0900221int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
222 void (*dofunc)(struct inode *, __u64,
223 struct buffer_head *,
224 struct buffer_head *))
225{
226 struct buffer_head *header_bh, *bh;
227 int ret;
228
229 if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) {
230 printk(KERN_WARNING "%s: invalid segment number: %llu\n",
231 __func__, (unsigned long long)segnum);
232 return -EINVAL;
233 }
234 down_write(&NILFS_MDT(sufile)->mi_sem);
235
236 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
237 if (ret < 0)
238 goto out_sem;
239
240 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, create, &bh);
241 if (!ret) {
242 dofunc(sufile, segnum, header_bh, bh);
243 brelse(bh);
244 }
245 brelse(header_bh);
246
247 out_sem:
248 up_write(&NILFS_MDT(sufile)->mi_sem);
249 return ret;
250}
251
Koji Sato6c98cd42009-04-06 19:01:32 -0700252/**
Ryusuke Konishi619205d2011-05-05 01:23:57 +0900253 * nilfs_sufile_set_alloc_range - limit range of segment to be allocated
254 * @sufile: inode of segment usage file
255 * @start: minimum segment number of allocatable region (inclusive)
256 * @end: maximum segment number of allocatable region (inclusive)
257 *
258 * Return Value: On success, 0 is returned. On error, one of the
259 * following negative error codes is returned.
260 *
261 * %-ERANGE - invalid segment region
262 */
263int nilfs_sufile_set_alloc_range(struct inode *sufile, __u64 start, __u64 end)
264{
265 struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
266 __u64 nsegs;
267 int ret = -ERANGE;
268
269 down_write(&NILFS_MDT(sufile)->mi_sem);
270 nsegs = nilfs_sufile_get_nsegments(sufile);
271
272 if (start <= end && end < nsegs) {
273 sui->allocmin = start;
274 sui->allocmax = end;
275 ret = 0;
276 }
277 up_write(&NILFS_MDT(sufile)->mi_sem);
278 return ret;
279}
280
281/**
Koji Sato6c98cd42009-04-06 19:01:32 -0700282 * nilfs_sufile_alloc - allocate a segment
283 * @sufile: inode of segment usage file
284 * @segnump: pointer to segment number
285 *
286 * Description: nilfs_sufile_alloc() allocates a clean segment.
287 *
288 * Return Value: On success, 0 is returned and the segment number of the
289 * allocated segment is stored in the place pointed by @segnump. On error, one
290 * of the following negative error codes is returned.
291 *
292 * %-EIO - I/O error.
293 *
294 * %-ENOMEM - Insufficient amount of memory available.
295 *
296 * %-ENOSPC - No clean segment left.
297 */
298int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump)
299{
300 struct buffer_head *header_bh, *su_bh;
Koji Sato6c98cd42009-04-06 19:01:32 -0700301 struct nilfs_sufile_header *header;
302 struct nilfs_segment_usage *su;
Ryusuke Konishi619205d2011-05-05 01:23:57 +0900303 struct nilfs_sufile_info *sui = NILFS_SUI(sufile);
Koji Sato6c98cd42009-04-06 19:01:32 -0700304 size_t susz = NILFS_MDT(sufile)->mi_entry_size;
305 __u64 segnum, maxsegnum, last_alloc;
306 void *kaddr;
Ryusuke Konishi619205d2011-05-05 01:23:57 +0900307 unsigned long nsegments, ncleansegs, nsus, cnt;
308 int ret, j;
Koji Sato6c98cd42009-04-06 19:01:32 -0700309
310 down_write(&NILFS_MDT(sufile)->mi_sem);
311
Koji Sato6c98cd42009-04-06 19:01:32 -0700312 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
313 if (ret < 0)
314 goto out_sem;
315 kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
Ryusuke Konishi7b16c8a2009-11-13 03:10:21 +0900316 header = kaddr + bh_offset(header_bh);
Koji Sato6c98cd42009-04-06 19:01:32 -0700317 ncleansegs = le64_to_cpu(header->sh_ncleansegs);
318 last_alloc = le64_to_cpu(header->sh_last_alloc);
319 kunmap_atomic(kaddr, KM_USER0);
320
321 nsegments = nilfs_sufile_get_nsegments(sufile);
Ryusuke Konishi619205d2011-05-05 01:23:57 +0900322 maxsegnum = sui->allocmax;
Koji Sato6c98cd42009-04-06 19:01:32 -0700323 segnum = last_alloc + 1;
Ryusuke Konishi619205d2011-05-05 01:23:57 +0900324 if (segnum < sui->allocmin || segnum > sui->allocmax)
325 segnum = sui->allocmin;
326
327 for (cnt = 0; cnt < nsegments; cnt += nsus) {
328 if (segnum > maxsegnum) {
329 if (cnt < sui->allocmax - sui->allocmin + 1) {
330 /*
331 * wrap around in the limited region.
332 * if allocation started from
333 * sui->allocmin, this never happens.
334 */
335 segnum = sui->allocmin;
336 maxsegnum = last_alloc;
337 } else if (segnum > sui->allocmin &&
338 sui->allocmax + 1 < nsegments) {
339 segnum = sui->allocmax + 1;
340 maxsegnum = nsegments - 1;
341 } else if (sui->allocmin > 0) {
342 segnum = 0;
343 maxsegnum = sui->allocmin - 1;
344 } else {
345 break; /* never happens */
346 }
Koji Sato6c98cd42009-04-06 19:01:32 -0700347 }
348 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1,
349 &su_bh);
350 if (ret < 0)
351 goto out_header;
352 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
353 su = nilfs_sufile_block_get_segment_usage(
354 sufile, segnum, su_bh, kaddr);
355
356 nsus = nilfs_sufile_segment_usages_in_block(
357 sufile, segnum, maxsegnum);
358 for (j = 0; j < nsus; j++, su = (void *)su + susz, segnum++) {
359 if (!nilfs_segment_usage_clean(su))
360 continue;
361 /* found a clean segment */
Koji Sato6c98cd42009-04-06 19:01:32 -0700362 nilfs_segment_usage_set_dirty(su);
363 kunmap_atomic(kaddr, KM_USER0);
364
365 kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
Ryusuke Konishi7b16c8a2009-11-13 03:10:21 +0900366 header = kaddr + bh_offset(header_bh);
Koji Sato6c98cd42009-04-06 19:01:32 -0700367 le64_add_cpu(&header->sh_ncleansegs, -1);
368 le64_add_cpu(&header->sh_ndirtysegs, 1);
369 header->sh_last_alloc = cpu_to_le64(segnum);
370 kunmap_atomic(kaddr, KM_USER0);
371
Ryusuke Konishi619205d2011-05-05 01:23:57 +0900372 sui->ncleansegs--;
Koji Sato6c98cd42009-04-06 19:01:32 -0700373 nilfs_mdt_mark_buffer_dirty(header_bh);
374 nilfs_mdt_mark_buffer_dirty(su_bh);
375 nilfs_mdt_mark_dirty(sufile);
376 brelse(su_bh);
377 *segnump = segnum;
378 goto out_header;
379 }
380
381 kunmap_atomic(kaddr, KM_USER0);
382 brelse(su_bh);
383 }
384
385 /* no segments left */
386 ret = -ENOSPC;
387
388 out_header:
389 brelse(header_bh);
390
391 out_sem:
392 up_write(&NILFS_MDT(sufile)->mi_sem);
393 return ret;
394}
395
Ryusuke Konishia7030182009-04-05 18:24:11 +0900396void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
397 struct buffer_head *header_bh,
398 struct buffer_head *su_bh)
Koji Sato6c98cd42009-04-06 19:01:32 -0700399{
Koji Sato6c98cd42009-04-06 19:01:32 -0700400 struct nilfs_segment_usage *su;
401 void *kaddr;
Koji Sato6c98cd42009-04-06 19:01:32 -0700402
403 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900404 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700405 if (unlikely(!nilfs_segment_usage_clean(su))) {
406 printk(KERN_WARNING "%s: segment %llu must be clean\n",
Koji Sato6c98cd42009-04-06 19:01:32 -0700407 __func__, (unsigned long long)segnum);
Ryusuke Konishi1f5abe72009-04-06 19:01:55 -0700408 kunmap_atomic(kaddr, KM_USER0);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900409 return;
Koji Sato6c98cd42009-04-06 19:01:32 -0700410 }
411 nilfs_segment_usage_set_dirty(su);
412 kunmap_atomic(kaddr, KM_USER0);
413
Ryusuke Konishia7030182009-04-05 18:24:11 +0900414 nilfs_sufile_mod_counter(header_bh, -1, 1);
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900415 NILFS_SUI(sufile)->ncleansegs--;
416
Koji Sato6c98cd42009-04-06 19:01:32 -0700417 nilfs_mdt_mark_buffer_dirty(su_bh);
418 nilfs_mdt_mark_dirty(sufile);
Koji Sato6c98cd42009-04-06 19:01:32 -0700419}
420
Ryusuke Konishic85399c2009-04-05 18:30:58 +0900421void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
422 struct buffer_head *header_bh,
423 struct buffer_head *su_bh)
424{
425 struct nilfs_segment_usage *su;
426 void *kaddr;
427 int clean, dirty;
428
429 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
430 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
431 if (su->su_flags == cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY) &&
432 su->su_nblocks == cpu_to_le32(0)) {
433 kunmap_atomic(kaddr, KM_USER0);
434 return;
435 }
436 clean = nilfs_segment_usage_clean(su);
437 dirty = nilfs_segment_usage_dirty(su);
438
439 /* make the segment garbage */
440 su->su_lastmod = cpu_to_le64(0);
441 su->su_nblocks = cpu_to_le32(0);
442 su->su_flags = cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY);
443 kunmap_atomic(kaddr, KM_USER0);
444
445 nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1);
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900446 NILFS_SUI(sufile)->ncleansegs -= clean;
447
Ryusuke Konishic85399c2009-04-05 18:30:58 +0900448 nilfs_mdt_mark_buffer_dirty(su_bh);
449 nilfs_mdt_mark_dirty(sufile);
450}
451
Ryusuke Konishia7030182009-04-05 18:24:11 +0900452void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
453 struct buffer_head *header_bh,
454 struct buffer_head *su_bh)
Koji Sato6c98cd42009-04-06 19:01:32 -0700455{
Koji Sato6c98cd42009-04-06 19:01:32 -0700456 struct nilfs_segment_usage *su;
457 void *kaddr;
Ryusuke Konishia7030182009-04-05 18:24:11 +0900458 int sudirty;
Koji Sato6c98cd42009-04-06 19:01:32 -0700459
Ryusuke Konishia7030182009-04-05 18:24:11 +0900460 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
461 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
462 if (nilfs_segment_usage_clean(su)) {
463 printk(KERN_WARNING "%s: segment %llu is already clean\n",
464 __func__, (unsigned long long)segnum);
Koji Sato6c98cd42009-04-06 19:01:32 -0700465 kunmap_atomic(kaddr, KM_USER0);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900466 return;
Koji Sato6c98cd42009-04-06 19:01:32 -0700467 }
Ryusuke Konishia7030182009-04-05 18:24:11 +0900468 WARN_ON(nilfs_segment_usage_error(su));
469 WARN_ON(!nilfs_segment_usage_dirty(su));
470
471 sudirty = nilfs_segment_usage_dirty(su);
472 nilfs_segment_usage_set_clean(su);
Koji Sato6c98cd42009-04-06 19:01:32 -0700473 kunmap_atomic(kaddr, KM_USER0);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900474 nilfs_mdt_mark_buffer_dirty(su_bh);
475
476 nilfs_sufile_mod_counter(header_bh, 1, sudirty ? (u64)-1 : 0);
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900477 NILFS_SUI(sufile)->ncleansegs++;
478
Koji Sato6c98cd42009-04-06 19:01:32 -0700479 nilfs_mdt_mark_dirty(sufile);
Koji Sato6c98cd42009-04-06 19:01:32 -0700480}
481
482/**
Ryusuke Konishi61a189e2009-11-18 17:25:12 +0900483 * nilfs_sufile_mark_dirty - mark the buffer having a segment usage dirty
484 * @sufile: inode of segment usage file
485 * @segnum: segment number
486 */
487int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum)
488{
489 struct buffer_head *bh;
490 int ret;
491
492 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
493 if (!ret) {
494 nilfs_mdt_mark_buffer_dirty(bh);
495 nilfs_mdt_mark_dirty(sufile);
496 brelse(bh);
497 }
498 return ret;
499}
500
501/**
Ryusuke Konishi071ec542009-11-18 18:23:34 +0900502 * nilfs_sufile_set_segment_usage - set usage of a segment
503 * @sufile: inode of segment usage file
504 * @segnum: segment number
505 * @nblocks: number of live blocks in the segment
506 * @modtime: modification time (option)
507 */
508int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
509 unsigned long nblocks, time_t modtime)
510{
511 struct buffer_head *bh;
512 struct nilfs_segment_usage *su;
513 void *kaddr;
514 int ret;
515
516 down_write(&NILFS_MDT(sufile)->mi_sem);
517 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
518 if (ret < 0)
519 goto out_sem;
520
521 kaddr = kmap_atomic(bh->b_page, KM_USER0);
522 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
523 WARN_ON(nilfs_segment_usage_error(su));
524 if (modtime)
525 su->su_lastmod = cpu_to_le64(modtime);
526 su->su_nblocks = cpu_to_le32(nblocks);
527 kunmap_atomic(kaddr, KM_USER0);
528
529 nilfs_mdt_mark_buffer_dirty(bh);
530 nilfs_mdt_mark_dirty(sufile);
531 brelse(bh);
532
533 out_sem:
534 up_write(&NILFS_MDT(sufile)->mi_sem);
535 return ret;
536}
537
538/**
Koji Sato6c98cd42009-04-06 19:01:32 -0700539 * nilfs_sufile_get_stat - get segment usage statistics
540 * @sufile: inode of segment usage file
541 * @stat: pointer to a structure of segment usage statistics
542 *
543 * Description: nilfs_sufile_get_stat() returns information about segment
544 * usage.
545 *
546 * Return Value: On success, 0 is returned, and segment usage information is
547 * stored in the place pointed by @stat. On error, one of the following
548 * negative error codes is returned.
549 *
550 * %-EIO - I/O error.
551 *
552 * %-ENOMEM - Insufficient amount of memory available.
553 */
554int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat)
555{
556 struct buffer_head *header_bh;
557 struct nilfs_sufile_header *header;
Ryusuke Konishic6e07182010-09-05 00:23:50 +0900558 struct the_nilfs *nilfs = NILFS_I_NILFS(sufile);
Koji Sato6c98cd42009-04-06 19:01:32 -0700559 void *kaddr;
560 int ret;
561
562 down_read(&NILFS_MDT(sufile)->mi_sem);
563
564 ret = nilfs_sufile_get_header_block(sufile, &header_bh);
565 if (ret < 0)
566 goto out_sem;
567
568 kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
Ryusuke Konishi7b16c8a2009-11-13 03:10:21 +0900569 header = kaddr + bh_offset(header_bh);
Koji Sato6c98cd42009-04-06 19:01:32 -0700570 sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile);
571 sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs);
572 sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs);
Ryusuke Konishi2c2e52f2009-04-06 19:01:54 -0700573 sustat->ss_ctime = nilfs->ns_ctime;
574 sustat->ss_nongc_ctime = nilfs->ns_nongc_ctime;
575 spin_lock(&nilfs->ns_last_segment_lock);
576 sustat->ss_prot_seq = nilfs->ns_prot_seq;
577 spin_unlock(&nilfs->ns_last_segment_lock);
Koji Sato6c98cd42009-04-06 19:01:32 -0700578 kunmap_atomic(kaddr, KM_USER0);
579 brelse(header_bh);
580
581 out_sem:
582 up_read(&NILFS_MDT(sufile)->mi_sem);
583 return ret;
584}
585
Ryusuke Konishia7030182009-04-05 18:24:11 +0900586void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
587 struct buffer_head *header_bh,
588 struct buffer_head *su_bh)
Koji Sato6c98cd42009-04-06 19:01:32 -0700589{
Koji Sato6c98cd42009-04-06 19:01:32 -0700590 struct nilfs_segment_usage *su;
Koji Sato6c98cd42009-04-06 19:01:32 -0700591 void *kaddr;
Ryusuke Konishia7030182009-04-05 18:24:11 +0900592 int suclean;
Koji Sato6c98cd42009-04-06 19:01:32 -0700593
594 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
595 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
596 if (nilfs_segment_usage_error(su)) {
597 kunmap_atomic(kaddr, KM_USER0);
Ryusuke Konishia7030182009-04-05 18:24:11 +0900598 return;
Koji Sato6c98cd42009-04-06 19:01:32 -0700599 }
Ryusuke Konishi88072fa2009-04-05 15:03:16 +0900600 suclean = nilfs_segment_usage_clean(su);
Koji Sato6c98cd42009-04-06 19:01:32 -0700601 nilfs_segment_usage_set_error(su);
602 kunmap_atomic(kaddr, KM_USER0);
Koji Sato6c98cd42009-04-06 19:01:32 -0700603
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900604 if (suclean) {
Ryusuke Konishia7030182009-04-05 18:24:11 +0900605 nilfs_sufile_mod_counter(header_bh, -1, 0);
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900606 NILFS_SUI(sufile)->ncleansegs--;
607 }
Koji Sato6c98cd42009-04-06 19:01:32 -0700608 nilfs_mdt_mark_buffer_dirty(su_bh);
609 nilfs_mdt_mark_dirty(sufile);
Koji Sato6c98cd42009-04-06 19:01:32 -0700610}
611
612/**
613 * nilfs_sufile_get_suinfo -
614 * @sufile: inode of segment usage file
615 * @segnum: segment number to start looking
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900616 * @buf: array of suinfo
617 * @sisz: byte size of suinfo
Koji Sato6c98cd42009-04-06 19:01:32 -0700618 * @nsi: size of suinfo array
619 *
620 * Description:
621 *
622 * Return Value: On success, 0 is returned and .... On error, one of the
623 * following negative error codes is returned.
624 *
625 * %-EIO - I/O error.
626 *
627 * %-ENOMEM - Insufficient amount of memory available.
628 */
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900629ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
630 unsigned sisz, size_t nsi)
Koji Sato6c98cd42009-04-06 19:01:32 -0700631{
632 struct buffer_head *su_bh;
633 struct nilfs_segment_usage *su;
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900634 struct nilfs_suinfo *si = buf;
Koji Sato6c98cd42009-04-06 19:01:32 -0700635 size_t susz = NILFS_MDT(sufile)->mi_entry_size;
Ryusuke Konishic6e07182010-09-05 00:23:50 +0900636 struct the_nilfs *nilfs = NILFS_I_NILFS(sufile);
Koji Sato6c98cd42009-04-06 19:01:32 -0700637 void *kaddr;
638 unsigned long nsegs, segusages_per_block;
639 ssize_t n;
640 int ret, i, j;
641
642 down_read(&NILFS_MDT(sufile)->mi_sem);
643
644 segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile);
645 nsegs = min_t(unsigned long,
646 nilfs_sufile_get_nsegments(sufile) - segnum,
647 nsi);
648 for (i = 0; i < nsegs; i += n, segnum += n) {
649 n = min_t(unsigned long,
650 segusages_per_block -
651 nilfs_sufile_get_offset(sufile, segnum),
652 nsegs - i);
653 ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0,
654 &su_bh);
655 if (ret < 0) {
656 if (ret != -ENOENT)
657 goto out;
658 /* hole */
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900659 memset(si, 0, sisz * n);
660 si = (void *)si + sisz * n;
Koji Sato6c98cd42009-04-06 19:01:32 -0700661 continue;
662 }
663
664 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
665 su = nilfs_sufile_block_get_segment_usage(
666 sufile, segnum, su_bh, kaddr);
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900667 for (j = 0; j < n;
668 j++, su = (void *)su + susz, si = (void *)si + sisz) {
669 si->sui_lastmod = le64_to_cpu(su->su_lastmod);
670 si->sui_nblocks = le32_to_cpu(su->su_nblocks);
671 si->sui_flags = le32_to_cpu(su->su_flags) &
Ryusuke Konishicece5522009-04-06 19:01:58 -0700672 ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
Ryusuke Konishi3efb55b2009-03-30 00:50:19 +0900673 if (nilfs_segment_is_active(nilfs, segnum + j))
Ryusuke Konishi003ff182009-05-12 03:58:47 +0900674 si->sui_flags |=
Ryusuke Konishicece5522009-04-06 19:01:58 -0700675 (1UL << NILFS_SEGMENT_USAGE_ACTIVE);
Koji Sato6c98cd42009-04-06 19:01:32 -0700676 }
677 kunmap_atomic(kaddr, KM_USER0);
678 brelse(su_bh);
679 }
680 ret = nsegs;
681
682 out:
683 up_read(&NILFS_MDT(sufile)->mi_sem);
684 return ret;
685}
Ryusuke Konishi79739562009-11-12 23:56:43 +0900686
687/**
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900688 * nilfs_sufile_read - read or get sufile inode
689 * @sb: super block instance
690 * @susize: size of a segment usage entry
Ryusuke Konishi8707df32009-11-13 01:36:56 +0900691 * @raw_inode: on-disk sufile inode
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900692 * @inodep: buffer to store the inode
Ryusuke Konishi8707df32009-11-13 01:36:56 +0900693 */
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900694int nilfs_sufile_read(struct super_block *sb, size_t susize,
695 struct nilfs_inode *raw_inode, struct inode **inodep)
Ryusuke Konishi8707df32009-11-13 01:36:56 +0900696{
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900697 struct inode *sufile;
698 struct nilfs_sufile_info *sui;
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900699 struct buffer_head *header_bh;
700 struct nilfs_sufile_header *header;
701 void *kaddr;
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900702 int err;
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900703
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900704 sufile = nilfs_iget_locked(sb, NULL, NILFS_SUFILE_INO);
705 if (unlikely(!sufile))
706 return -ENOMEM;
707 if (!(sufile->i_state & I_NEW))
708 goto out;
Ryusuke Konishiaa474a22009-11-13 03:41:55 +0900709
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900710 err = nilfs_mdt_init(sufile, NILFS_MDT_GFP, sizeof(*sui));
711 if (err)
712 goto failed;
Ryusuke Konishi8707df32009-11-13 01:36:56 +0900713
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900714 nilfs_mdt_set_entry_size(sufile, susize,
715 sizeof(struct nilfs_sufile_header));
Ryusuke Konishi79739562009-11-12 23:56:43 +0900716
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900717 err = nilfs_read_inode_common(sufile, raw_inode);
718 if (err)
719 goto failed;
720
721 err = nilfs_sufile_get_header_block(sufile, &header_bh);
722 if (err)
723 goto failed;
724
725 sui = NILFS_SUI(sufile);
726 kaddr = kmap_atomic(header_bh->b_page, KM_USER0);
727 header = kaddr + bh_offset(header_bh);
728 sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs);
729 kunmap_atomic(kaddr, KM_USER0);
730 brelse(header_bh);
731
Ryusuke Konishi619205d2011-05-05 01:23:57 +0900732 sui->allocmax = nilfs_sufile_get_nsegments(sufile) - 1;
733 sui->allocmin = 0;
734
Ryusuke Konishif1e89c82010-09-05 12:20:59 +0900735 unlock_new_inode(sufile);
736 out:
737 *inodep = sufile;
738 return 0;
739 failed:
740 iget_failed(sufile);
741 return err;
Ryusuke Konishi79739562009-11-12 23:56:43 +0900742}