diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2009-05-11 14:58:47 -0400 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2009-06-10 10:41:11 -0400 |
commit | 003ff182fddde09ddfb8d079bbdb02f9d2122082 (patch) | |
tree | d949fa673353767d8854355987e49d82821935f6 /fs/nilfs2/cpfile.c | |
parent | 258ef67e246fd548e7ad91c23004ad157c03cce5 (diff) |
nilfs2: allow future expansion of metadata read out via get info ioctl
Nilfs has some ioctl commands to read out metadata from meta data
files:
- NILFS_IOCTL_GET_CPINFO for checkpoint file,
- NILFS_IOCTL_GET_SUINFO for segment usage file, and
- NILFS_IOCTL_GET_VINFO for Disk Address Transalation (DAT) file,
respectively.
Every routine on these metadata files is implemented so that it allows
future expansion of on-disk format. But, the above ioctl commands do
not support expansion even though nilfs_argv structure can handle
arbitrary size for data exchanged via ioctl.
This allows future expansion of the following structures which give
basic format of the "get information" ioctls:
- struct nilfs_cpinfo
- struct nilfs_suinfo
- struct nilfs_vinfo
So, this introduces forward compatility of such ioctl commands.
In this patch, a sanity check in nilfs_ioctl_get_info() function is
changed to accept larger data structure [1], and metadata read
routines are rewritten so that they become compatible for larger
structures; the routines will just ignore the remaining fields which
the current version of nilfs doesn't know.
[1] The ioctl function already has another upper limit (PAGE_SIZE
against a structure, which appears in nilfs_ioctl_wrap_copy
function), and this will not cause security problem.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2/cpfile.c')
-rw-r--r-- | fs/nilfs2/cpfile.c | 33 |
1 files changed, 21 insertions, 12 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 300f1cdfa862..b5a8cd6b474f 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c | |||
@@ -384,9 +384,10 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile, | |||
384 | } | 384 | } |
385 | 385 | ||
386 | static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, | 386 | static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, |
387 | struct nilfs_cpinfo *ci, size_t nci) | 387 | void *buf, unsigned cisz, size_t nci) |
388 | { | 388 | { |
389 | struct nilfs_checkpoint *cp; | 389 | struct nilfs_checkpoint *cp; |
390 | struct nilfs_cpinfo *ci = buf; | ||
390 | struct buffer_head *bh; | 391 | struct buffer_head *bh; |
391 | size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; | 392 | size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; |
392 | __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; | 393 | __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; |
@@ -410,17 +411,22 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, | |||
410 | kaddr = kmap_atomic(bh->b_page, KM_USER0); | 411 | kaddr = kmap_atomic(bh->b_page, KM_USER0); |
411 | cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); | 412 | cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); |
412 | for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { | 413 | for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { |
413 | if (!nilfs_checkpoint_invalid(cp)) | 414 | if (!nilfs_checkpoint_invalid(cp)) { |
414 | nilfs_cpfile_checkpoint_to_cpinfo( | 415 | nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, |
415 | cpfile, cp, &ci[n++]); | 416 | ci); |
417 | ci = (void *)ci + cisz; | ||
418 | n++; | ||
419 | } | ||
416 | } | 420 | } |
417 | kunmap_atomic(kaddr, KM_USER0); | 421 | kunmap_atomic(kaddr, KM_USER0); |
418 | brelse(bh); | 422 | brelse(bh); |
419 | } | 423 | } |
420 | 424 | ||
421 | ret = n; | 425 | ret = n; |
422 | if (n > 0) | 426 | if (n > 0) { |
423 | *cnop = ci[n - 1].ci_cno + 1; | 427 | ci = (void *)ci - cisz; |
428 | *cnop = ci->ci_cno + 1; | ||
429 | } | ||
424 | 430 | ||
425 | out: | 431 | out: |
426 | up_read(&NILFS_MDT(cpfile)->mi_sem); | 432 | up_read(&NILFS_MDT(cpfile)->mi_sem); |
@@ -428,11 +434,12 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, | |||
428 | } | 434 | } |
429 | 435 | ||
430 | static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, | 436 | static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, |
431 | struct nilfs_cpinfo *ci, size_t nci) | 437 | void *buf, unsigned cisz, size_t nci) |
432 | { | 438 | { |
433 | struct buffer_head *bh; | 439 | struct buffer_head *bh; |
434 | struct nilfs_cpfile_header *header; | 440 | struct nilfs_cpfile_header *header; |
435 | struct nilfs_checkpoint *cp; | 441 | struct nilfs_checkpoint *cp; |
442 | struct nilfs_cpinfo *ci = buf; | ||
436 | __u64 curr = *cnop, next; | 443 | __u64 curr = *cnop, next; |
437 | unsigned long curr_blkoff, next_blkoff; | 444 | unsigned long curr_blkoff, next_blkoff; |
438 | void *kaddr; | 445 | void *kaddr; |
@@ -472,7 +479,9 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, | |||
472 | if (unlikely(nilfs_checkpoint_invalid(cp) || | 479 | if (unlikely(nilfs_checkpoint_invalid(cp) || |
473 | !nilfs_checkpoint_snapshot(cp))) | 480 | !nilfs_checkpoint_snapshot(cp))) |
474 | break; | 481 | break; |
475 | nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n++]); | 482 | nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci); |
483 | ci = (void *)ci + cisz; | ||
484 | n++; | ||
476 | next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); | 485 | next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); |
477 | if (next == 0) | 486 | if (next == 0) |
478 | break; /* reach end of the snapshot list */ | 487 | break; /* reach end of the snapshot list */ |
@@ -511,13 +520,13 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, | |||
511 | */ | 520 | */ |
512 | 521 | ||
513 | ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, | 522 | ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, |
514 | struct nilfs_cpinfo *ci, size_t nci) | 523 | void *buf, unsigned cisz, size_t nci) |
515 | { | 524 | { |
516 | switch (mode) { | 525 | switch (mode) { |
517 | case NILFS_CHECKPOINT: | 526 | case NILFS_CHECKPOINT: |
518 | return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, ci, nci); | 527 | return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci); |
519 | case NILFS_SNAPSHOT: | 528 | case NILFS_SNAPSHOT: |
520 | return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci); | 529 | return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci); |
521 | default: | 530 | default: |
522 | return -EINVAL; | 531 | return -EINVAL; |
523 | } | 532 | } |
@@ -535,7 +544,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) | |||
535 | ssize_t nci; | 544 | ssize_t nci; |
536 | int ret; | 545 | int ret; |
537 | 546 | ||
538 | nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, 1); | 547 | nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1); |
539 | if (nci < 0) | 548 | if (nci < 0) |
540 | return nci; | 549 | return nci; |
541 | else if (nci == 0 || ci.ci_cno != cno) | 550 | else if (nci == 0 || ci.ci_cno != cno) |