aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/cpfile.c
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-05-11 14:58:47 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-06-10 10:41:11 -0400
commit003ff182fddde09ddfb8d079bbdb02f9d2122082 (patch)
treed949fa673353767d8854355987e49d82821935f6 /fs/nilfs2/cpfile.c
parent258ef67e246fd548e7ad91c23004ad157c03cce5 (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.c33
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
386static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, 386static 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
430static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, 436static 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
513ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, 522ssize_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)