Blame view
fs/nilfs2/cpfile.c
26.1 KB
296198097 nilfs2: checkpoin... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* * cpfile.c - NILFS checkpoint file. * * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Written by Koji Sato <koji@osrg.net>. */ #include <linux/kernel.h> #include <linux/fs.h> #include <linux/string.h> #include <linux/buffer_head.h> #include <linux/errno.h> #include <linux/nilfs2_fs.h> #include "mdt.h" #include "cpfile.h" static inline unsigned long nilfs_cpfile_checkpoints_per_block(const struct inode *cpfile) { return NILFS_MDT(cpfile)->mi_entries_per_block; } /* block number from the beginning of the file */ static unsigned long nilfs_cpfile_get_blkoff(const struct inode *cpfile, __u64 cno) { |
1f5abe7e7 nilfs2: replace B... |
43 |
__u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1; |
296198097 nilfs2: checkpoin... |
44 45 46 47 48 49 50 51 52 53 54 |
do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile)); return (unsigned long)tcno; } /* offset in block */ static unsigned long nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno) { __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1; return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile)); } |
53a2c3bdf nilfs2: improve e... |
55 56 57 58 59 60 |
static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile, unsigned long blkoff) { return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff + 1 - NILFS_MDT(cpfile)->mi_first_entry_offset; } |
296198097 nilfs2: checkpoin... |
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
static unsigned long nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile, __u64 curr, __u64 max) { return min_t(__u64, nilfs_cpfile_checkpoints_per_block(cpfile) - nilfs_cpfile_get_offset(cpfile, curr), max - curr); } static inline int nilfs_cpfile_is_in_first(const struct inode *cpfile, __u64 cno) { return nilfs_cpfile_get_blkoff(cpfile, cno) == 0; } static unsigned int nilfs_cpfile_block_add_valid_checkpoints(const struct inode *cpfile, struct buffer_head *bh, void *kaddr, unsigned int n) { struct nilfs_checkpoint *cp = kaddr + bh_offset(bh); unsigned int count; count = le32_to_cpu(cp->cp_checkpoints_count) + n; cp->cp_checkpoints_count = cpu_to_le32(count); return count; } static unsigned int nilfs_cpfile_block_sub_valid_checkpoints(const struct inode *cpfile, struct buffer_head *bh, void *kaddr, unsigned int n) { struct nilfs_checkpoint *cp = kaddr + bh_offset(bh); unsigned int count; |
1f5abe7e7 nilfs2: replace B... |
100 |
WARN_ON(le32_to_cpu(cp->cp_checkpoints_count) < n); |
296198097 nilfs2: checkpoin... |
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
count = le32_to_cpu(cp->cp_checkpoints_count) - n; cp->cp_checkpoints_count = cpu_to_le32(count); return count; } static inline struct nilfs_cpfile_header * nilfs_cpfile_block_get_header(const struct inode *cpfile, struct buffer_head *bh, void *kaddr) { return kaddr + bh_offset(bh); } static struct nilfs_checkpoint * nilfs_cpfile_block_get_checkpoint(const struct inode *cpfile, __u64 cno, struct buffer_head *bh, void *kaddr) { return kaddr + bh_offset(bh) + nilfs_cpfile_get_offset(cpfile, cno) * NILFS_MDT(cpfile)->mi_entry_size; } static void nilfs_cpfile_block_init(struct inode *cpfile, struct buffer_head *bh, void *kaddr) { struct nilfs_checkpoint *cp = kaddr + bh_offset(bh); size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; int n = nilfs_cpfile_checkpoints_per_block(cpfile); while (n-- > 0) { nilfs_checkpoint_set_invalid(cp); cp = (void *)cp + cpsz; } } static inline int nilfs_cpfile_get_header_block(struct inode *cpfile, struct buffer_head **bhp) { return nilfs_mdt_get_block(cpfile, 0, 0, NULL, bhp); } static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile, __u64 cno, int create, struct buffer_head **bhp) { return nilfs_mdt_get_block(cpfile, nilfs_cpfile_get_blkoff(cpfile, cno), create, nilfs_cpfile_block_init, bhp); } |
53a2c3bdf nilfs2: improve e... |
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
/** * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile * @cpfile: inode of cpfile * @start_cno: start checkpoint number (inclusive) * @end_cno: end checkpoint number (inclusive) * @cnop: place to store the next checkpoint number * @bhp: place to store a pointer to buffer_head struct * * Return Value: On success, it returns 0. On error, the following negative * error code is returned. * * %-ENOMEM - Insufficient memory available. * * %-EIO - I/O error * * %-ENOENT - no block exists in the range. */ static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile, __u64 start_cno, __u64 end_cno, __u64 *cnop, struct buffer_head **bhp) { unsigned long start, end, blkoff; int ret; if (unlikely(start_cno > end_cno)) return -ENOENT; start = nilfs_cpfile_get_blkoff(cpfile, start_cno); end = nilfs_cpfile_get_blkoff(cpfile, end_cno); ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp); if (!ret) *cnop = (blkoff == start) ? start_cno : nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff); return ret; } |
296198097 nilfs2: checkpoin... |
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile, __u64 cno) { return nilfs_mdt_delete_block(cpfile, nilfs_cpfile_get_blkoff(cpfile, cno)); } /** * nilfs_cpfile_get_checkpoint - get a checkpoint * @cpfile: inode of checkpoint file * @cno: checkpoint number * @create: create flag * @cpp: pointer to a checkpoint * @bhp: pointer to a buffer head * * Description: nilfs_cpfile_get_checkpoint() acquires the checkpoint * specified by @cno. A new checkpoint will be created if @cno is the current * checkpoint number and @create is nonzero. * * Return Value: On success, 0 is returned, and the checkpoint and the * buffer head of the buffer on which the checkpoint is located are stored in * the place pointed by @cpp and @bhp, respectively. On error, one of the * following negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-ENOENT - No such checkpoint. |
1f5abe7e7 nilfs2: replace B... |
218 219 |
* * %-EINVAL - invalid checkpoint. |
296198097 nilfs2: checkpoin... |
220 221 222 223 224 225 226 227 228 229 230 231 |
*/ int nilfs_cpfile_get_checkpoint(struct inode *cpfile, __u64 cno, int create, struct nilfs_checkpoint **cpp, struct buffer_head **bhp) { struct buffer_head *header_bh, *cp_bh; struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp; void *kaddr; int ret; |
1f5abe7e7 nilfs2: replace B... |
232 233 234 |
if (unlikely(cno < 1 || cno > nilfs_mdt_cno(cpfile) || (cno < nilfs_mdt_cno(cpfile) && create))) return -EINVAL; |
296198097 nilfs2: checkpoin... |
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
down_write(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); if (ret < 0) goto out_sem; ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, create, &cp_bh); if (ret < 0) goto out_header; kaddr = kmap(cp_bh->b_page); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); if (nilfs_checkpoint_invalid(cp)) { if (!create) { kunmap(cp_bh->b_page); brelse(cp_bh); ret = -ENOENT; goto out_header; } /* a newly-created checkpoint */ nilfs_checkpoint_clear_invalid(cp); if (!nilfs_cpfile_is_in_first(cpfile, cno)) nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh, kaddr, 1); |
5fc7b1417 nilfs2: use mark_... |
258 |
mark_buffer_dirty(cp_bh); |
296198097 nilfs2: checkpoin... |
259 |
|
7b9c0976a nilfs2: remove th... |
260 |
kaddr = kmap_atomic(header_bh->b_page); |
296198097 nilfs2: checkpoin... |
261 262 263 |
header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); le64_add_cpu(&header->ch_ncheckpoints, 1); |
7b9c0976a nilfs2: remove th... |
264 |
kunmap_atomic(kaddr); |
5fc7b1417 nilfs2: use mark_... |
265 |
mark_buffer_dirty(header_bh); |
296198097 nilfs2: checkpoin... |
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
nilfs_mdt_mark_dirty(cpfile); } if (cpp != NULL) *cpp = cp; *bhp = cp_bh; out_header: brelse(header_bh); out_sem: up_write(&NILFS_MDT(cpfile)->mi_sem); return ret; } /** * nilfs_cpfile_put_checkpoint - put a checkpoint * @cpfile: inode of checkpoint file * @cno: checkpoint number * @bh: buffer head * * Description: nilfs_cpfile_put_checkpoint() releases the checkpoint * specified by @cno. @bh must be the buffer head which has been returned by * a previous call to nilfs_cpfile_get_checkpoint() with @cno. */ void nilfs_cpfile_put_checkpoint(struct inode *cpfile, __u64 cno, struct buffer_head *bh) { kunmap(bh->b_page); brelse(bh); } /** * nilfs_cpfile_delete_checkpoints - delete checkpoints * @cpfile: inode of checkpoint file * @start: start checkpoint number * @end: end checkpoint numer * * Description: nilfs_cpfile_delete_checkpoints() deletes the checkpoints in * the period from @start to @end, excluding @end itself. The checkpoints * which have been already deleted are ignored. * * Return Value: On success, 0 is returned. On error, one of the following * negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-EINVAL - invalid checkpoints. */ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, __u64 start, __u64 end) { struct buffer_head *header_bh, *cp_bh; struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp; size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; __u64 cno; void *kaddr; unsigned long tnicps; |
fe0627e7b nilfs2: fix timin... |
328 |
int ret, ncps, nicps, nss, count, i; |
296198097 nilfs2: checkpoin... |
329 |
|
1f5abe7e7 nilfs2: replace B... |
330 331 332 333 334 335 |
if (unlikely(start == 0 || start > end)) { printk(KERN_ERR "%s: invalid range of checkpoint numbers: " "[%llu, %llu) ", __func__, (unsigned long long)start, (unsigned long long)end); return -EINVAL; |
296198097 nilfs2: checkpoin... |
336 |
} |
296198097 nilfs2: checkpoin... |
337 338 339 340 341 342 |
down_write(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); if (ret < 0) goto out_sem; tnicps = 0; |
fe0627e7b nilfs2: fix timin... |
343 |
nss = 0; |
296198097 nilfs2: checkpoin... |
344 345 346 347 348 349 |
for (cno = start; cno < end; cno += ncps) { ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end); ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); if (ret < 0) { if (ret != -ENOENT) |
d9a0a345a nilfs2: fix disor... |
350 |
break; |
296198097 nilfs2: checkpoin... |
351 352 353 354 |
/* skip hole */ ret = 0; continue; } |
7b9c0976a nilfs2: remove th... |
355 |
kaddr = kmap_atomic(cp_bh->b_page); |
296198097 nilfs2: checkpoin... |
356 357 358 359 |
cp = nilfs_cpfile_block_get_checkpoint( cpfile, cno, cp_bh, kaddr); nicps = 0; for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) { |
fe0627e7b nilfs2: fix timin... |
360 361 362 |
if (nilfs_checkpoint_snapshot(cp)) { nss++; } else if (!nilfs_checkpoint_invalid(cp)) { |
296198097 nilfs2: checkpoin... |
363 364 365 366 367 368 |
nilfs_checkpoint_set_invalid(cp); nicps++; } } if (nicps > 0) { tnicps += nicps; |
5fc7b1417 nilfs2: use mark_... |
369 |
mark_buffer_dirty(cp_bh); |
296198097 nilfs2: checkpoin... |
370 |
nilfs_mdt_mark_dirty(cpfile); |
5ee581483 nilfs2: trivial c... |
371 372 373 374 375 376 |
if (!nilfs_cpfile_is_in_first(cpfile, cno)) { count = nilfs_cpfile_block_sub_valid_checkpoints( cpfile, cp_bh, kaddr, nicps); if (count == 0) { /* make hole */ |
7b9c0976a nilfs2: remove th... |
377 |
kunmap_atomic(kaddr); |
5ee581483 nilfs2: trivial c... |
378 379 380 381 382 383 384 385 386 387 388 389 |
brelse(cp_bh); ret = nilfs_cpfile_delete_checkpoint_block( cpfile, cno); if (ret == 0) continue; printk(KERN_ERR "%s: cannot delete block ", __func__); break; } |
296198097 nilfs2: checkpoin... |
390 391 |
} } |
7b9c0976a nilfs2: remove th... |
392 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
393 394 395 396 |
brelse(cp_bh); } if (tnicps > 0) { |
7b9c0976a nilfs2: remove th... |
397 |
kaddr = kmap_atomic(header_bh->b_page); |
296198097 nilfs2: checkpoin... |
398 399 |
header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); |
6c98cd4ec nilfs2: segment u... |
400 |
le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps); |
5fc7b1417 nilfs2: use mark_... |
401 |
mark_buffer_dirty(header_bh); |
296198097 nilfs2: checkpoin... |
402 |
nilfs_mdt_mark_dirty(cpfile); |
7b9c0976a nilfs2: remove th... |
403 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
404 |
} |
62013ab5d nilfs2: fix bh le... |
405 |
|
296198097 nilfs2: checkpoin... |
406 |
brelse(header_bh); |
fe0627e7b nilfs2: fix timin... |
407 408 |
if (nss > 0) ret = -EBUSY; |
296198097 nilfs2: checkpoin... |
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
out_sem: up_write(&NILFS_MDT(cpfile)->mi_sem); return ret; } static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile, struct nilfs_checkpoint *cp, struct nilfs_cpinfo *ci) { ci->ci_flags = le32_to_cpu(cp->cp_flags); ci->ci_cno = le64_to_cpu(cp->cp_cno); ci->ci_create = le64_to_cpu(cp->cp_create); ci->ci_nblk_inc = le64_to_cpu(cp->cp_nblk_inc); ci->ci_inodes_count = le64_to_cpu(cp->cp_inodes_count); ci->ci_blocks_count = le64_to_cpu(cp->cp_blocks_count); ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); } |
76068c4ff nilfs2: fix buggy... |
427 |
static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, |
003ff182f nilfs2: allow fut... |
428 |
void *buf, unsigned cisz, size_t nci) |
296198097 nilfs2: checkpoin... |
429 430 |
{ struct nilfs_checkpoint *cp; |
003ff182f nilfs2: allow fut... |
431 |
struct nilfs_cpinfo *ci = buf; |
296198097 nilfs2: checkpoin... |
432 433 |
struct buffer_head *bh; size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; |
76068c4ff nilfs2: fix buggy... |
434 |
__u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; |
296198097 nilfs2: checkpoin... |
435 436 437 |
void *kaddr; int n, ret; int ncps, i; |
1f5abe7e7 nilfs2: replace B... |
438 439 |
if (cno == 0) return -ENOENT; /* checkpoint number 0 is invalid */ |
296198097 nilfs2: checkpoin... |
440 |
down_read(&NILFS_MDT(cpfile)->mi_sem); |
53a2c3bdf nilfs2: improve e... |
441 442 443 |
for (n = 0; n < nci; cno += ncps) { ret = nilfs_cpfile_find_checkpoint_block( cpfile, cno, cur_cno - 1, &cno, &bh); |
296198097 nilfs2: checkpoin... |
444 |
if (ret < 0) { |
53a2c3bdf nilfs2: improve e... |
445 446 447 |
if (likely(ret == -ENOENT)) break; goto out; |
296198097 nilfs2: checkpoin... |
448 |
} |
53a2c3bdf nilfs2: improve e... |
449 |
ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno); |
296198097 nilfs2: checkpoin... |
450 |
|
7b9c0976a nilfs2: remove th... |
451 |
kaddr = kmap_atomic(bh->b_page); |
296198097 nilfs2: checkpoin... |
452 453 |
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { |
003ff182f nilfs2: allow fut... |
454 455 456 457 458 459 |
if (!nilfs_checkpoint_invalid(cp)) { nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci); ci = (void *)ci + cisz; n++; } |
296198097 nilfs2: checkpoin... |
460 |
} |
7b9c0976a nilfs2: remove th... |
461 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
462 463 464 465 |
brelse(bh); } ret = n; |
003ff182f nilfs2: allow fut... |
466 467 468 469 |
if (n > 0) { ci = (void *)ci - cisz; *cnop = ci->ci_cno + 1; } |
296198097 nilfs2: checkpoin... |
470 471 472 473 474 |
out: up_read(&NILFS_MDT(cpfile)->mi_sem); return ret; } |
b028fcfc4 nilfs2: fix gc fa... |
475 |
static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, |
003ff182f nilfs2: allow fut... |
476 |
void *buf, unsigned cisz, size_t nci) |
296198097 nilfs2: checkpoin... |
477 478 479 480 |
{ struct buffer_head *bh; struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp; |
003ff182f nilfs2: allow fut... |
481 |
struct nilfs_cpinfo *ci = buf; |
b028fcfc4 nilfs2: fix gc fa... |
482 |
__u64 curr = *cnop, next; |
296198097 nilfs2: checkpoin... |
483 484 |
unsigned long curr_blkoff, next_blkoff; void *kaddr; |
7fa10d200 nilfs2: fix impro... |
485 |
int n = 0, ret; |
296198097 nilfs2: checkpoin... |
486 487 |
down_read(&NILFS_MDT(cpfile)->mi_sem); |
b028fcfc4 nilfs2: fix gc fa... |
488 |
if (curr == 0) { |
296198097 nilfs2: checkpoin... |
489 490 491 |
ret = nilfs_cpfile_get_header_block(cpfile, &bh); if (ret < 0) goto out; |
7b9c0976a nilfs2: remove th... |
492 |
kaddr = kmap_atomic(bh->b_page); |
296198097 nilfs2: checkpoin... |
493 494 |
header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr); curr = le64_to_cpu(header->ch_snapshot_list.ssl_next); |
7b9c0976a nilfs2: remove th... |
495 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
496 497 498 499 500 |
brelse(bh); if (curr == 0) { ret = 0; goto out; } |
b028fcfc4 nilfs2: fix gc fa... |
501 502 503 504 |
} else if (unlikely(curr == ~(__u64)0)) { ret = 0; goto out; } |
296198097 nilfs2: checkpoin... |
505 506 |
curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr); ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh); |
7fa10d200 nilfs2: fix impro... |
507 508 509 |
if (unlikely(ret < 0)) { if (ret == -ENOENT) ret = 0; /* No snapshots (started from a hole block) */ |
296198097 nilfs2: checkpoin... |
510 |
goto out; |
7fa10d200 nilfs2: fix impro... |
511 |
} |
7b9c0976a nilfs2: remove th... |
512 |
kaddr = kmap_atomic(bh->b_page); |
7fa10d200 nilfs2: fix impro... |
513 514 515 516 517 |
while (n < nci) { cp = nilfs_cpfile_block_get_checkpoint(cpfile, curr, bh, kaddr); curr = ~(__u64)0; /* Terminator */ if (unlikely(nilfs_checkpoint_invalid(cp) || !nilfs_checkpoint_snapshot(cp))) |
296198097 nilfs2: checkpoin... |
518 |
break; |
003ff182f nilfs2: allow fut... |
519 520 521 |
nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci); ci = (void *)ci + cisz; n++; |
7fa10d200 nilfs2: fix impro... |
522 523 524 |
next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); if (next == 0) break; /* reach end of the snapshot list */ |
296198097 nilfs2: checkpoin... |
525 526 |
next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next); if (curr_blkoff != next_blkoff) { |
7b9c0976a nilfs2: remove th... |
527 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
528 529 530 |
brelse(bh); ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0, &bh); |
7fa10d200 nilfs2: fix impro... |
531 532 |
if (unlikely(ret < 0)) { WARN_ON(ret == -ENOENT); |
296198097 nilfs2: checkpoin... |
533 |
goto out; |
7fa10d200 nilfs2: fix impro... |
534 |
} |
7b9c0976a nilfs2: remove th... |
535 |
kaddr = kmap_atomic(bh->b_page); |
296198097 nilfs2: checkpoin... |
536 537 538 539 |
} curr = next; curr_blkoff = next_blkoff; } |
7b9c0976a nilfs2: remove th... |
540 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
541 |
brelse(bh); |
b028fcfc4 nilfs2: fix gc fa... |
542 |
*cnop = curr; |
296198097 nilfs2: checkpoin... |
543 544 545 546 547 548 549 550 551 552 553 554 555 556 |
ret = n; out: up_read(&NILFS_MDT(cpfile)->mi_sem); return ret; } /** * nilfs_cpfile_get_cpinfo - * @cpfile: * @cno: * @ci: * @nci: */ |
b028fcfc4 nilfs2: fix gc fa... |
557 558 |
ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, |
003ff182f nilfs2: allow fut... |
559 |
void *buf, unsigned cisz, size_t nci) |
296198097 nilfs2: checkpoin... |
560 561 562 |
{ switch (mode) { case NILFS_CHECKPOINT: |
003ff182f nilfs2: allow fut... |
563 |
return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci); |
296198097 nilfs2: checkpoin... |
564 |
case NILFS_SNAPSHOT: |
003ff182f nilfs2: allow fut... |
565 |
return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci); |
296198097 nilfs2: checkpoin... |
566 567 568 569 570 571 572 573 574 575 576 577 578 |
default: return -EINVAL; } } /** * nilfs_cpfile_delete_checkpoint - * @cpfile: * @cno: */ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) { struct nilfs_cpinfo ci; |
76068c4ff nilfs2: fix buggy... |
579 |
__u64 tcno = cno; |
296198097 nilfs2: checkpoin... |
580 |
ssize_t nci; |
296198097 nilfs2: checkpoin... |
581 |
|
003ff182f nilfs2: allow fut... |
582 |
nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1); |
296198097 nilfs2: checkpoin... |
583 584 585 586 |
if (nci < 0) return nci; else if (nci == 0 || ci.ci_cno != cno) return -ENOENT; |
30c25be71 nilfs2: return EB... |
587 588 |
else if (nilfs_cpinfo_snapshot(&ci)) return -EBUSY; |
296198097 nilfs2: checkpoin... |
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 |
return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1); } static struct nilfs_snapshot_list * nilfs_cpfile_block_get_snapshot_list(const struct inode *cpfile, __u64 cno, struct buffer_head *bh, void *kaddr) { struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp; struct nilfs_snapshot_list *list; if (cno != 0) { cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); list = &cp->cp_snapshot_list; } else { header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr); list = &header->ch_snapshot_list; } return list; } static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno) { struct buffer_head *header_bh, *curr_bh, *prev_bh, *cp_bh; struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp; struct nilfs_snapshot_list *list; __u64 curr, prev; unsigned long curr_blkoff, prev_blkoff; void *kaddr; int ret; |
1f5abe7e7 nilfs2: replace B... |
623 624 |
if (cno == 0) return -ENOENT; /* checkpoint number 0 is invalid */ |
296198097 nilfs2: checkpoin... |
625 626 627 628 629 |
down_write(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); if (ret < 0) goto out_sem; |
7b9c0976a nilfs2: remove th... |
630 |
kaddr = kmap_atomic(cp_bh->b_page); |
296198097 nilfs2: checkpoin... |
631 632 633 |
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); if (nilfs_checkpoint_invalid(cp)) { ret = -ENOENT; |
7b9c0976a nilfs2: remove th... |
634 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
635 636 637 638 |
goto out_cp; } if (nilfs_checkpoint_snapshot(cp)) { ret = 0; |
7b9c0976a nilfs2: remove th... |
639 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
640 641 |
goto out_cp; } |
7b9c0976a nilfs2: remove th... |
642 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
643 644 645 646 |
ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); if (ret < 0) goto out_cp; |
7b9c0976a nilfs2: remove th... |
647 |
kaddr = kmap_atomic(header_bh->b_page); |
296198097 nilfs2: checkpoin... |
648 649 650 651 652 653 654 655 656 657 658 |
header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); list = &header->ch_snapshot_list; curr_bh = header_bh; get_bh(curr_bh); curr = 0; curr_blkoff = 0; prev = le64_to_cpu(list->ssl_prev); while (prev > cno) { prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev); curr = prev; if (curr_blkoff != prev_blkoff) { |
7b9c0976a nilfs2: remove th... |
659 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
660 661 662 663 664 |
brelse(curr_bh); ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &curr_bh); if (ret < 0) goto out_header; |
7b9c0976a nilfs2: remove th... |
665 |
kaddr = kmap_atomic(curr_bh->b_page); |
296198097 nilfs2: checkpoin... |
666 667 668 669 670 671 672 |
} curr_blkoff = prev_blkoff; cp = nilfs_cpfile_block_get_checkpoint( cpfile, curr, curr_bh, kaddr); list = &cp->cp_snapshot_list; prev = le64_to_cpu(list->ssl_prev); } |
7b9c0976a nilfs2: remove th... |
673 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
674 675 676 677 678 679 680 681 682 683 |
if (prev != 0) { ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0, &prev_bh); if (ret < 0) goto out_curr; } else { prev_bh = header_bh; get_bh(prev_bh); } |
7b9c0976a nilfs2: remove th... |
684 |
kaddr = kmap_atomic(curr_bh->b_page); |
296198097 nilfs2: checkpoin... |
685 686 687 |
list = nilfs_cpfile_block_get_snapshot_list( cpfile, curr, curr_bh, kaddr); list->ssl_prev = cpu_to_le64(cno); |
7b9c0976a nilfs2: remove th... |
688 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
689 |
|
7b9c0976a nilfs2: remove th... |
690 |
kaddr = kmap_atomic(cp_bh->b_page); |
296198097 nilfs2: checkpoin... |
691 692 693 694 |
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr); cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev); nilfs_checkpoint_set_snapshot(cp); |
7b9c0976a nilfs2: remove th... |
695 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
696 |
|
7b9c0976a nilfs2: remove th... |
697 |
kaddr = kmap_atomic(prev_bh->b_page); |
296198097 nilfs2: checkpoin... |
698 699 700 |
list = nilfs_cpfile_block_get_snapshot_list( cpfile, prev, prev_bh, kaddr); list->ssl_next = cpu_to_le64(cno); |
7b9c0976a nilfs2: remove th... |
701 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
702 |
|
7b9c0976a nilfs2: remove th... |
703 |
kaddr = kmap_atomic(header_bh->b_page); |
296198097 nilfs2: checkpoin... |
704 705 |
header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); le64_add_cpu(&header->ch_nsnapshots, 1); |
7b9c0976a nilfs2: remove th... |
706 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
707 |
|
5fc7b1417 nilfs2: use mark_... |
708 709 710 711 |
mark_buffer_dirty(prev_bh); mark_buffer_dirty(curr_bh); mark_buffer_dirty(cp_bh); mark_buffer_dirty(header_bh); |
296198097 nilfs2: checkpoin... |
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 |
nilfs_mdt_mark_dirty(cpfile); brelse(prev_bh); out_curr: brelse(curr_bh); out_header: brelse(header_bh); out_cp: brelse(cp_bh); out_sem: up_write(&NILFS_MDT(cpfile)->mi_sem); return ret; } static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno) { struct buffer_head *header_bh, *next_bh, *prev_bh, *cp_bh; struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp; struct nilfs_snapshot_list *list; __u64 next, prev; void *kaddr; int ret; |
1f5abe7e7 nilfs2: replace B... |
739 740 |
if (cno == 0) return -ENOENT; /* checkpoint number 0 is invalid */ |
296198097 nilfs2: checkpoin... |
741 742 743 744 745 |
down_write(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); if (ret < 0) goto out_sem; |
7b9c0976a nilfs2: remove th... |
746 |
kaddr = kmap_atomic(cp_bh->b_page); |
296198097 nilfs2: checkpoin... |
747 748 749 |
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); if (nilfs_checkpoint_invalid(cp)) { ret = -ENOENT; |
7b9c0976a nilfs2: remove th... |
750 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
751 752 753 754 |
goto out_cp; } if (!nilfs_checkpoint_snapshot(cp)) { ret = 0; |
7b9c0976a nilfs2: remove th... |
755 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
756 757 758 759 760 761 |
goto out_cp; } list = &cp->cp_snapshot_list; next = le64_to_cpu(list->ssl_next); prev = le64_to_cpu(list->ssl_prev); |
7b9c0976a nilfs2: remove th... |
762 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 |
ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); if (ret < 0) goto out_cp; if (next != 0) { ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0, &next_bh); if (ret < 0) goto out_header; } else { next_bh = header_bh; get_bh(next_bh); } if (prev != 0) { ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0, &prev_bh); if (ret < 0) goto out_next; } else { prev_bh = header_bh; get_bh(prev_bh); } |
7b9c0976a nilfs2: remove th... |
785 |
kaddr = kmap_atomic(next_bh->b_page); |
296198097 nilfs2: checkpoin... |
786 787 788 |
list = nilfs_cpfile_block_get_snapshot_list( cpfile, next, next_bh, kaddr); list->ssl_prev = cpu_to_le64(prev); |
7b9c0976a nilfs2: remove th... |
789 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
790 |
|
7b9c0976a nilfs2: remove th... |
791 |
kaddr = kmap_atomic(prev_bh->b_page); |
296198097 nilfs2: checkpoin... |
792 793 794 |
list = nilfs_cpfile_block_get_snapshot_list( cpfile, prev, prev_bh, kaddr); list->ssl_next = cpu_to_le64(next); |
7b9c0976a nilfs2: remove th... |
795 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
796 |
|
7b9c0976a nilfs2: remove th... |
797 |
kaddr = kmap_atomic(cp_bh->b_page); |
296198097 nilfs2: checkpoin... |
798 799 800 801 |
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); cp->cp_snapshot_list.ssl_next = cpu_to_le64(0); cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0); nilfs_checkpoint_clear_snapshot(cp); |
7b9c0976a nilfs2: remove th... |
802 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
803 |
|
7b9c0976a nilfs2: remove th... |
804 |
kaddr = kmap_atomic(header_bh->b_page); |
296198097 nilfs2: checkpoin... |
805 806 |
header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); le64_add_cpu(&header->ch_nsnapshots, -1); |
7b9c0976a nilfs2: remove th... |
807 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
808 |
|
5fc7b1417 nilfs2: use mark_... |
809 810 811 812 |
mark_buffer_dirty(next_bh); mark_buffer_dirty(prev_bh); mark_buffer_dirty(cp_bh); mark_buffer_dirty(header_bh); |
296198097 nilfs2: checkpoin... |
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 |
nilfs_mdt_mark_dirty(cpfile); brelse(prev_bh); out_next: brelse(next_bh); out_header: brelse(header_bh); out_cp: brelse(cp_bh); out_sem: up_write(&NILFS_MDT(cpfile)->mi_sem); return ret; } /** * nilfs_cpfile_is_snapshot - * @cpfile: inode of checkpoint file * @cno: checkpoint number * * Description: * * Return Value: On success, 1 is returned if the checkpoint specified by * @cno is a snapshot, or 0 if not. On error, one of the following negative * error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-ENOENT - No such checkpoint. */ int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno) { struct buffer_head *bh; struct nilfs_checkpoint *cp; void *kaddr; int ret; |
43be0ec03 nilfs2: add more ... |
854 855 856 857 |
/* CP number is invalid if it's zero or larger than the largest exist one.*/ if (cno == 0 || cno >= nilfs_mdt_cno(cpfile)) return -ENOENT; |
296198097 nilfs2: checkpoin... |
858 859 860 861 862 |
down_read(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); if (ret < 0) goto out; |
7b9c0976a nilfs2: remove th... |
863 |
kaddr = kmap_atomic(bh->b_page); |
296198097 nilfs2: checkpoin... |
864 |
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); |
43be0ec03 nilfs2: add more ... |
865 866 867 868 |
if (nilfs_checkpoint_invalid(cp)) ret = -ENOENT; else ret = nilfs_checkpoint_snapshot(cp); |
7b9c0976a nilfs2: remove th... |
869 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 |
brelse(bh); out: up_read(&NILFS_MDT(cpfile)->mi_sem); return ret; } /** * nilfs_cpfile_change_cpmode - change checkpoint mode * @cpfile: inode of checkpoint file * @cno: checkpoint number * @status: mode of checkpoint * * Description: nilfs_change_cpmode() changes the mode of the checkpoint * specified by @cno. The mode @mode is NILFS_CHECKPOINT or NILFS_SNAPSHOT. * * Return Value: On success, 0 is returned. On error, one of the following * negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. * * %-ENOENT - No such checkpoint. */ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) { |
296198097 nilfs2: checkpoin... |
897 |
int ret; |
296198097 nilfs2: checkpoin... |
898 899 |
switch (mode) { case NILFS_CHECKPOINT: |
032dbb3b5 nilfs2: see state... |
900 901 902 903 904 905 906 |
if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno)) /* * Current implementation does not have to protect * plain read-only mounts since they are exclusive * with a read/write mount and are protected from the * cleaner. */ |
296198097 nilfs2: checkpoin... |
907 |
ret = -EBUSY; |
032dbb3b5 nilfs2: see state... |
908 |
else |
296198097 nilfs2: checkpoin... |
909 |
ret = nilfs_cpfile_clear_snapshot(cpfile, cno); |
296198097 nilfs2: checkpoin... |
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 |
return ret; case NILFS_SNAPSHOT: return nilfs_cpfile_set_snapshot(cpfile, cno); default: return -EINVAL; } } /** * nilfs_cpfile_get_stat - get checkpoint statistics * @cpfile: inode of checkpoint file * @stat: pointer to a structure of checkpoint statistics * * Description: nilfs_cpfile_get_stat() returns information about checkpoints. * * Return Value: On success, 0 is returned, and checkpoints information is * stored in the place pointed by @stat. On error, one of the following * negative error codes is returned. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient amount of memory available. */ int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat) { struct buffer_head *bh; struct nilfs_cpfile_header *header; void *kaddr; int ret; down_read(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_header_block(cpfile, &bh); if (ret < 0) goto out_sem; |
7b9c0976a nilfs2: remove th... |
945 |
kaddr = kmap_atomic(bh->b_page); |
296198097 nilfs2: checkpoin... |
946 947 948 949 |
header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr); cpstat->cs_cno = nilfs_mdt_cno(cpfile); cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints); cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots); |
7b9c0976a nilfs2: remove th... |
950 |
kunmap_atomic(kaddr); |
296198097 nilfs2: checkpoin... |
951 952 953 954 955 956 |
brelse(bh); out_sem: up_read(&NILFS_MDT(cpfile)->mi_sem); return ret; } |
79739565e nilfs2: separate ... |
957 958 |
/** |
f1e89c86f nilfs2: use iget ... |
959 960 |
* nilfs_cpfile_read - read or get cpfile inode * @sb: super block instance |
79739565e nilfs2: separate ... |
961 |
* @cpsize: size of a checkpoint entry |
f1e89c86f nilfs2: use iget ... |
962 963 |
* @raw_inode: on-disk cpfile inode * @inodep: buffer to store the inode |
79739565e nilfs2: separate ... |
964 |
*/ |
f1e89c86f nilfs2: use iget ... |
965 966 |
int nilfs_cpfile_read(struct super_block *sb, size_t cpsize, struct nilfs_inode *raw_inode, struct inode **inodep) |
79739565e nilfs2: separate ... |
967 968 |
{ struct inode *cpfile; |
f1e89c86f nilfs2: use iget ... |
969 |
int err; |
79739565e nilfs2: separate ... |
970 |
|
0ec060d18 nilfs2: verify me... |
971 972 973 974 975 976 977 978 979 980 981 982 983 |
if (cpsize > sb->s_blocksize) { printk(KERN_ERR "NILFS: too large checkpoint size: %zu bytes. ", cpsize); return -EINVAL; } else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) { printk(KERN_ERR "NILFS: too small checkpoint size: %zu bytes. ", cpsize); return -EINVAL; } |
f1e89c86f nilfs2: use iget ... |
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 |
cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO); if (unlikely(!cpfile)) return -ENOMEM; if (!(cpfile->i_state & I_NEW)) goto out; err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0); if (err) goto failed; nilfs_mdt_set_entry_size(cpfile, cpsize, sizeof(struct nilfs_cpfile_header)); err = nilfs_read_inode_common(cpfile, raw_inode); if (err) goto failed; unlock_new_inode(cpfile); out: *inodep = cpfile; return 0; failed: iget_failed(cpfile); return err; |
79739565e nilfs2: separate ... |
1008 |
} |