]>
Commit | Line | Data |
---|---|---|
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>. | |
21 | */ | |
22 | ||
23 | #include <linux/kernel.h> | |
24 | #include <linux/fs.h> | |
25 | #include <linux/string.h> | |
26 | #include <linux/buffer_head.h> | |
27 | #include <linux/errno.h> | |
28 | #include <linux/nilfs2_fs.h> | |
29 | #include "mdt.h" | |
30 | #include "sufile.h" | |
31 | ||
32 | ||
33 | static inline unsigned long | |
34 | nilfs_sufile_segment_usages_per_block(const struct inode *sufile) | |
35 | { | |
36 | return NILFS_MDT(sufile)->mi_entries_per_block; | |
37 | } | |
38 | ||
39 | static unsigned long | |
40 | nilfs_sufile_get_blkoff(const struct inode *sufile, __u64 segnum) | |
41 | { | |
42 | __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset; | |
43 | do_div(t, nilfs_sufile_segment_usages_per_block(sufile)); | |
44 | return (unsigned long)t; | |
45 | } | |
46 | ||
47 | static unsigned long | |
48 | nilfs_sufile_get_offset(const struct inode *sufile, __u64 segnum) | |
49 | { | |
50 | __u64 t = segnum + NILFS_MDT(sufile)->mi_first_entry_offset; | |
51 | return do_div(t, nilfs_sufile_segment_usages_per_block(sufile)); | |
52 | } | |
53 | ||
54 | static unsigned long | |
55 | nilfs_sufile_segment_usages_in_block(const struct inode *sufile, __u64 curr, | |
56 | __u64 max) | |
57 | { | |
58 | return min_t(unsigned long, | |
59 | nilfs_sufile_segment_usages_per_block(sufile) - | |
60 | nilfs_sufile_get_offset(sufile, curr), | |
61 | max - curr + 1); | |
62 | } | |
63 | ||
64 | static inline struct nilfs_sufile_header * | |
65 | nilfs_sufile_block_get_header(const struct inode *sufile, | |
66 | struct buffer_head *bh, | |
67 | void *kaddr) | |
68 | { | |
69 | return kaddr + bh_offset(bh); | |
70 | } | |
71 | ||
72 | static struct nilfs_segment_usage * | |
73 | nilfs_sufile_block_get_segment_usage(const struct inode *sufile, __u64 segnum, | |
74 | struct buffer_head *bh, void *kaddr) | |
75 | { | |
76 | return kaddr + bh_offset(bh) + | |
77 | nilfs_sufile_get_offset(sufile, segnum) * | |
78 | NILFS_MDT(sufile)->mi_entry_size; | |
79 | } | |
80 | ||
81 | static inline int nilfs_sufile_get_header_block(struct inode *sufile, | |
82 | struct buffer_head **bhp) | |
83 | { | |
84 | return nilfs_mdt_get_block(sufile, 0, 0, NULL, bhp); | |
85 | } | |
86 | ||
87 | static inline int | |
88 | nilfs_sufile_get_segment_usage_block(struct inode *sufile, __u64 segnum, | |
89 | int create, struct buffer_head **bhp) | |
90 | { | |
91 | return nilfs_mdt_get_block(sufile, | |
92 | nilfs_sufile_get_blkoff(sufile, segnum), | |
93 | create, NULL, bhp); | |
94 | } | |
95 | ||
a703018f RK |
96 | static void nilfs_sufile_mod_counter(struct buffer_head *header_bh, |
97 | u64 ncleanadd, u64 ndirtyadd) | |
98 | { | |
99 | struct nilfs_sufile_header *header; | |
100 | void *kaddr; | |
101 | ||
102 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); | |
103 | header = kaddr + bh_offset(header_bh); | |
104 | le64_add_cpu(&header->sh_ncleansegs, ncleanadd); | |
105 | le64_add_cpu(&header->sh_ndirtysegs, ndirtyadd); | |
106 | kunmap_atomic(kaddr, KM_USER0); | |
107 | ||
108 | nilfs_mdt_mark_buffer_dirty(header_bh); | |
109 | } | |
110 | ||
111 | int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create, | |
112 | void (*dofunc)(struct inode *, __u64, | |
113 | struct buffer_head *, | |
114 | struct buffer_head *)) | |
115 | { | |
116 | struct buffer_head *header_bh, *bh; | |
117 | int ret; | |
118 | ||
119 | if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) { | |
120 | printk(KERN_WARNING "%s: invalid segment number: %llu\n", | |
121 | __func__, (unsigned long long)segnum); | |
122 | return -EINVAL; | |
123 | } | |
124 | down_write(&NILFS_MDT(sufile)->mi_sem); | |
125 | ||
126 | ret = nilfs_sufile_get_header_block(sufile, &header_bh); | |
127 | if (ret < 0) | |
128 | goto out_sem; | |
129 | ||
130 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, create, &bh); | |
131 | if (!ret) { | |
132 | dofunc(sufile, segnum, header_bh, bh); | |
133 | brelse(bh); | |
134 | } | |
135 | brelse(header_bh); | |
136 | ||
137 | out_sem: | |
138 | up_write(&NILFS_MDT(sufile)->mi_sem); | |
139 | return ret; | |
140 | } | |
141 | ||
6c98cd4e KS |
142 | /** |
143 | * nilfs_sufile_alloc - allocate a segment | |
144 | * @sufile: inode of segment usage file | |
145 | * @segnump: pointer to segment number | |
146 | * | |
147 | * Description: nilfs_sufile_alloc() allocates a clean segment. | |
148 | * | |
149 | * Return Value: On success, 0 is returned and the segment number of the | |
150 | * allocated segment is stored in the place pointed by @segnump. On error, one | |
151 | * of the following negative error codes is returned. | |
152 | * | |
153 | * %-EIO - I/O error. | |
154 | * | |
155 | * %-ENOMEM - Insufficient amount of memory available. | |
156 | * | |
157 | * %-ENOSPC - No clean segment left. | |
158 | */ | |
159 | int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) | |
160 | { | |
161 | struct buffer_head *header_bh, *su_bh; | |
6c98cd4e KS |
162 | struct nilfs_sufile_header *header; |
163 | struct nilfs_segment_usage *su; | |
164 | size_t susz = NILFS_MDT(sufile)->mi_entry_size; | |
165 | __u64 segnum, maxsegnum, last_alloc; | |
166 | void *kaddr; | |
167 | unsigned long nsegments, ncleansegs, nsus; | |
168 | int ret, i, j; | |
169 | ||
170 | down_write(&NILFS_MDT(sufile)->mi_sem); | |
171 | ||
6c98cd4e KS |
172 | ret = nilfs_sufile_get_header_block(sufile, &header_bh); |
173 | if (ret < 0) | |
174 | goto out_sem; | |
175 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); | |
176 | header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr); | |
177 | ncleansegs = le64_to_cpu(header->sh_ncleansegs); | |
178 | last_alloc = le64_to_cpu(header->sh_last_alloc); | |
179 | kunmap_atomic(kaddr, KM_USER0); | |
180 | ||
181 | nsegments = nilfs_sufile_get_nsegments(sufile); | |
182 | segnum = last_alloc + 1; | |
183 | maxsegnum = nsegments - 1; | |
184 | for (i = 0; i < nsegments; i += nsus) { | |
185 | if (segnum >= nsegments) { | |
186 | /* wrap around */ | |
187 | segnum = 0; | |
188 | maxsegnum = last_alloc; | |
189 | } | |
190 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1, | |
191 | &su_bh); | |
192 | if (ret < 0) | |
193 | goto out_header; | |
194 | kaddr = kmap_atomic(su_bh->b_page, KM_USER0); | |
195 | su = nilfs_sufile_block_get_segment_usage( | |
196 | sufile, segnum, su_bh, kaddr); | |
197 | ||
198 | nsus = nilfs_sufile_segment_usages_in_block( | |
199 | sufile, segnum, maxsegnum); | |
200 | for (j = 0; j < nsus; j++, su = (void *)su + susz, segnum++) { | |
201 | if (!nilfs_segment_usage_clean(su)) | |
202 | continue; | |
203 | /* found a clean segment */ | |
6c98cd4e KS |
204 | nilfs_segment_usage_set_dirty(su); |
205 | kunmap_atomic(kaddr, KM_USER0); | |
206 | ||
207 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); | |
208 | header = nilfs_sufile_block_get_header( | |
209 | sufile, header_bh, kaddr); | |
210 | le64_add_cpu(&header->sh_ncleansegs, -1); | |
211 | le64_add_cpu(&header->sh_ndirtysegs, 1); | |
212 | header->sh_last_alloc = cpu_to_le64(segnum); | |
213 | kunmap_atomic(kaddr, KM_USER0); | |
214 | ||
215 | nilfs_mdt_mark_buffer_dirty(header_bh); | |
216 | nilfs_mdt_mark_buffer_dirty(su_bh); | |
217 | nilfs_mdt_mark_dirty(sufile); | |
218 | brelse(su_bh); | |
219 | *segnump = segnum; | |
220 | goto out_header; | |
221 | } | |
222 | ||
223 | kunmap_atomic(kaddr, KM_USER0); | |
224 | brelse(su_bh); | |
225 | } | |
226 | ||
227 | /* no segments left */ | |
228 | ret = -ENOSPC; | |
229 | ||
230 | out_header: | |
231 | brelse(header_bh); | |
232 | ||
233 | out_sem: | |
234 | up_write(&NILFS_MDT(sufile)->mi_sem); | |
235 | return ret; | |
236 | } | |
237 | ||
a703018f RK |
238 | void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum, |
239 | struct buffer_head *header_bh, | |
240 | struct buffer_head *su_bh) | |
6c98cd4e | 241 | { |
6c98cd4e KS |
242 | struct nilfs_segment_usage *su; |
243 | void *kaddr; | |
6c98cd4e KS |
244 | |
245 | kaddr = kmap_atomic(su_bh->b_page, KM_USER0); | |
a703018f | 246 | su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr); |
1f5abe7e RK |
247 | if (unlikely(!nilfs_segment_usage_clean(su))) { |
248 | printk(KERN_WARNING "%s: segment %llu must be clean\n", | |
6c98cd4e | 249 | __func__, (unsigned long long)segnum); |
1f5abe7e | 250 | kunmap_atomic(kaddr, KM_USER0); |
a703018f | 251 | return; |
6c98cd4e KS |
252 | } |
253 | nilfs_segment_usage_set_dirty(su); | |
254 | kunmap_atomic(kaddr, KM_USER0); | |
255 | ||
a703018f | 256 | nilfs_sufile_mod_counter(header_bh, -1, 1); |
6c98cd4e KS |
257 | nilfs_mdt_mark_buffer_dirty(su_bh); |
258 | nilfs_mdt_mark_dirty(sufile); | |
6c98cd4e KS |
259 | } |
260 | ||
a703018f RK |
261 | void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum, |
262 | struct buffer_head *header_bh, | |
263 | struct buffer_head *su_bh) | |
6c98cd4e | 264 | { |
6c98cd4e KS |
265 | struct nilfs_segment_usage *su; |
266 | void *kaddr; | |
a703018f | 267 | int sudirty; |
6c98cd4e | 268 | |
a703018f RK |
269 | kaddr = kmap_atomic(su_bh->b_page, KM_USER0); |
270 | su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr); | |
271 | if (nilfs_segment_usage_clean(su)) { | |
272 | printk(KERN_WARNING "%s: segment %llu is already clean\n", | |
273 | __func__, (unsigned long long)segnum); | |
6c98cd4e | 274 | kunmap_atomic(kaddr, KM_USER0); |
a703018f | 275 | return; |
6c98cd4e | 276 | } |
a703018f RK |
277 | WARN_ON(nilfs_segment_usage_error(su)); |
278 | WARN_ON(!nilfs_segment_usage_dirty(su)); | |
6c98cd4e | 279 | |
a703018f RK |
280 | sudirty = nilfs_segment_usage_dirty(su); |
281 | nilfs_segment_usage_set_clean(su); | |
282 | kunmap_atomic(kaddr, KM_USER0); | |
283 | nilfs_mdt_mark_buffer_dirty(su_bh); | |
6c98cd4e | 284 | |
a703018f RK |
285 | nilfs_sufile_mod_counter(header_bh, 1, sudirty ? (u64)-1 : 0); |
286 | nilfs_mdt_mark_dirty(sufile); | |
6c98cd4e KS |
287 | } |
288 | ||
289 | /** | |
290 | * nilfs_sufile_get_segment_usage - get a segment usage | |
291 | * @sufile: inode of segment usage file | |
292 | * @segnum: segment number | |
293 | * @sup: pointer to segment usage | |
294 | * @bhp: pointer to buffer head | |
295 | * | |
296 | * Description: nilfs_sufile_get_segment_usage() acquires the segment usage | |
297 | * specified by @segnum. | |
298 | * | |
299 | * Return Value: On success, 0 is returned, and the segment usage and the | |
300 | * buffer head of the buffer on which the segment usage is located are stored | |
301 | * in the place pointed by @sup and @bhp, respectively. On error, one of the | |
302 | * following negative error codes is returned. | |
303 | * | |
304 | * %-EIO - I/O error. | |
305 | * | |
306 | * %-ENOMEM - Insufficient amount of memory available. | |
307 | * | |
308 | * %-EINVAL - Invalid segment usage number. | |
309 | */ | |
310 | int nilfs_sufile_get_segment_usage(struct inode *sufile, __u64 segnum, | |
311 | struct nilfs_segment_usage **sup, | |
312 | struct buffer_head **bhp) | |
313 | { | |
314 | struct buffer_head *bh; | |
315 | struct nilfs_segment_usage *su; | |
316 | void *kaddr; | |
317 | int ret; | |
318 | ||
319 | /* segnum is 0 origin */ | |
1f5abe7e RK |
320 | if (segnum >= nilfs_sufile_get_nsegments(sufile)) |
321 | return -EINVAL; | |
6c98cd4e KS |
322 | down_write(&NILFS_MDT(sufile)->mi_sem); |
323 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 1, &bh); | |
324 | if (ret < 0) | |
325 | goto out_sem; | |
326 | kaddr = kmap(bh->b_page); | |
327 | su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr); | |
328 | if (nilfs_segment_usage_error(su)) { | |
329 | kunmap(bh->b_page); | |
330 | brelse(bh); | |
331 | ret = -EINVAL; | |
332 | goto out_sem; | |
333 | } | |
334 | ||
335 | if (sup != NULL) | |
336 | *sup = su; | |
337 | *bhp = bh; | |
338 | ||
339 | out_sem: | |
340 | up_write(&NILFS_MDT(sufile)->mi_sem); | |
341 | return ret; | |
342 | } | |
343 | ||
344 | /** | |
345 | * nilfs_sufile_put_segment_usage - put a segment usage | |
346 | * @sufile: inode of segment usage file | |
347 | * @segnum: segment number | |
348 | * @bh: buffer head | |
349 | * | |
350 | * Description: nilfs_sufile_put_segment_usage() releases the segment usage | |
351 | * specified by @segnum. @bh must be the buffer head which have been returned | |
352 | * by a previous call to nilfs_sufile_get_segment_usage() with @segnum. | |
353 | */ | |
354 | void nilfs_sufile_put_segment_usage(struct inode *sufile, __u64 segnum, | |
355 | struct buffer_head *bh) | |
356 | { | |
357 | kunmap(bh->b_page); | |
358 | brelse(bh); | |
359 | } | |
360 | ||
361 | /** | |
362 | * nilfs_sufile_get_stat - get segment usage statistics | |
363 | * @sufile: inode of segment usage file | |
364 | * @stat: pointer to a structure of segment usage statistics | |
365 | * | |
366 | * Description: nilfs_sufile_get_stat() returns information about segment | |
367 | * usage. | |
368 | * | |
369 | * Return Value: On success, 0 is returned, and segment usage information is | |
370 | * stored in the place pointed by @stat. On error, one of the following | |
371 | * negative error codes is returned. | |
372 | * | |
373 | * %-EIO - I/O error. | |
374 | * | |
375 | * %-ENOMEM - Insufficient amount of memory available. | |
376 | */ | |
377 | int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat) | |
378 | { | |
379 | struct buffer_head *header_bh; | |
380 | struct nilfs_sufile_header *header; | |
2c2e52fc | 381 | struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; |
6c98cd4e KS |
382 | void *kaddr; |
383 | int ret; | |
384 | ||
385 | down_read(&NILFS_MDT(sufile)->mi_sem); | |
386 | ||
387 | ret = nilfs_sufile_get_header_block(sufile, &header_bh); | |
388 | if (ret < 0) | |
389 | goto out_sem; | |
390 | ||
391 | kaddr = kmap_atomic(header_bh->b_page, KM_USER0); | |
392 | header = nilfs_sufile_block_get_header(sufile, header_bh, kaddr); | |
393 | sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile); | |
394 | sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs); | |
395 | sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs); | |
2c2e52fc RK |
396 | sustat->ss_ctime = nilfs->ns_ctime; |
397 | sustat->ss_nongc_ctime = nilfs->ns_nongc_ctime; | |
398 | spin_lock(&nilfs->ns_last_segment_lock); | |
399 | sustat->ss_prot_seq = nilfs->ns_prot_seq; | |
400 | spin_unlock(&nilfs->ns_last_segment_lock); | |
6c98cd4e KS |
401 | kunmap_atomic(kaddr, KM_USER0); |
402 | brelse(header_bh); | |
403 | ||
404 | out_sem: | |
405 | up_read(&NILFS_MDT(sufile)->mi_sem); | |
406 | return ret; | |
407 | } | |
408 | ||
409 | /** | |
410 | * nilfs_sufile_get_ncleansegs - get the number of clean segments | |
411 | * @sufile: inode of segment usage file | |
412 | * @nsegsp: pointer to the number of clean segments | |
413 | * | |
414 | * Description: nilfs_sufile_get_ncleansegs() acquires the number of clean | |
415 | * segments. | |
416 | * | |
417 | * Return Value: On success, 0 is returned and the number of clean segments is | |
418 | * stored in the place pointed by @nsegsp. On error, one of the following | |
419 | * negative error codes is returned. | |
420 | * | |
421 | * %-EIO - I/O error. | |
422 | * | |
423 | * %-ENOMEM - Insufficient amount of memory available. | |
424 | */ | |
425 | int nilfs_sufile_get_ncleansegs(struct inode *sufile, unsigned long *nsegsp) | |
426 | { | |
427 | struct nilfs_sustat sustat; | |
428 | int ret; | |
429 | ||
430 | ret = nilfs_sufile_get_stat(sufile, &sustat); | |
431 | if (ret == 0) | |
432 | *nsegsp = sustat.ss_ncleansegs; | |
433 | return ret; | |
434 | } | |
435 | ||
a703018f RK |
436 | void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, |
437 | struct buffer_head *header_bh, | |
438 | struct buffer_head *su_bh) | |
6c98cd4e | 439 | { |
6c98cd4e | 440 | struct nilfs_segment_usage *su; |
6c98cd4e | 441 | void *kaddr; |
a703018f | 442 | int suclean; |
6c98cd4e KS |
443 | |
444 | kaddr = kmap_atomic(su_bh->b_page, KM_USER0); | |
445 | su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr); | |
446 | if (nilfs_segment_usage_error(su)) { | |
447 | kunmap_atomic(kaddr, KM_USER0); | |
a703018f | 448 | return; |
6c98cd4e | 449 | } |
88072faf | 450 | suclean = nilfs_segment_usage_clean(su); |
6c98cd4e KS |
451 | nilfs_segment_usage_set_error(su); |
452 | kunmap_atomic(kaddr, KM_USER0); | |
6c98cd4e | 453 | |
a703018f RK |
454 | if (suclean) |
455 | nilfs_sufile_mod_counter(header_bh, -1, 0); | |
6c98cd4e KS |
456 | nilfs_mdt_mark_buffer_dirty(su_bh); |
457 | nilfs_mdt_mark_dirty(sufile); | |
6c98cd4e KS |
458 | } |
459 | ||
460 | /** | |
461 | * nilfs_sufile_get_suinfo - | |
462 | * @sufile: inode of segment usage file | |
463 | * @segnum: segment number to start looking | |
464 | * @si: array of suinfo | |
465 | * @nsi: size of suinfo array | |
466 | * | |
467 | * Description: | |
468 | * | |
469 | * Return Value: On success, 0 is returned and .... On error, one of the | |
470 | * following negative error codes is returned. | |
471 | * | |
472 | * %-EIO - I/O error. | |
473 | * | |
474 | * %-ENOMEM - Insufficient amount of memory available. | |
475 | */ | |
476 | ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, | |
477 | struct nilfs_suinfo *si, size_t nsi) | |
478 | { | |
479 | struct buffer_head *su_bh; | |
480 | struct nilfs_segment_usage *su; | |
481 | size_t susz = NILFS_MDT(sufile)->mi_entry_size; | |
cece5520 | 482 | struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; |
6c98cd4e KS |
483 | void *kaddr; |
484 | unsigned long nsegs, segusages_per_block; | |
485 | ssize_t n; | |
486 | int ret, i, j; | |
487 | ||
488 | down_read(&NILFS_MDT(sufile)->mi_sem); | |
489 | ||
490 | segusages_per_block = nilfs_sufile_segment_usages_per_block(sufile); | |
491 | nsegs = min_t(unsigned long, | |
492 | nilfs_sufile_get_nsegments(sufile) - segnum, | |
493 | nsi); | |
494 | for (i = 0; i < nsegs; i += n, segnum += n) { | |
495 | n = min_t(unsigned long, | |
496 | segusages_per_block - | |
497 | nilfs_sufile_get_offset(sufile, segnum), | |
498 | nsegs - i); | |
499 | ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, | |
500 | &su_bh); | |
501 | if (ret < 0) { | |
502 | if (ret != -ENOENT) | |
503 | goto out; | |
504 | /* hole */ | |
505 | memset(&si[i], 0, sizeof(struct nilfs_suinfo) * n); | |
506 | continue; | |
507 | } | |
508 | ||
509 | kaddr = kmap_atomic(su_bh->b_page, KM_USER0); | |
510 | su = nilfs_sufile_block_get_segment_usage( | |
511 | sufile, segnum, su_bh, kaddr); | |
512 | for (j = 0; j < n; j++, su = (void *)su + susz) { | |
513 | si[i + j].sui_lastmod = le64_to_cpu(su->su_lastmod); | |
514 | si[i + j].sui_nblocks = le32_to_cpu(su->su_nblocks); | |
cece5520 RK |
515 | si[i + j].sui_flags = le32_to_cpu(su->su_flags) & |
516 | ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE); | |
3efb55b4 | 517 | if (nilfs_segment_is_active(nilfs, segnum + j)) |
cece5520 RK |
518 | si[i + j].sui_flags |= |
519 | (1UL << NILFS_SEGMENT_USAGE_ACTIVE); | |
6c98cd4e KS |
520 | } |
521 | kunmap_atomic(kaddr, KM_USER0); | |
522 | brelse(su_bh); | |
523 | } | |
524 | ret = nsegs; | |
525 | ||
526 | out: | |
527 | up_read(&NILFS_MDT(sufile)->mi_sem); | |
528 | return ret; | |
529 | } |