diff options
| author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-07-25 07:39:03 -0400 |
|---|---|---|
| committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-07-25 07:46:43 -0400 |
| commit | 6cda9fa2575ec0869fe77b0bdf295c0e51868cab (patch) | |
| tree | 09f160f79f2ab135cd0c9ce0a2099d96423e5e00 | |
| parent | c28e69d9332aab739920082a0a5677d861390824 (diff) | |
nilfs2: avoid rec_len overflow with 64KB block size
With 64KB blocksize, a directory entry can have size 64KB which does
not fit into 16 bits we have for entry length. So this patch stores
0xffff instead and converts value when read from / written to disk.
Nilfs derives its directory implementation from ext2 filesystem, and
this draws upon the corresponding change on ext2.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
| -rw-r--r-- | fs/nilfs2/dir.c | 26 | ||||
| -rw-r--r-- | include/linux/nilfs2_fs.h | 18 |
2 files changed, 32 insertions, 12 deletions
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index d8d183e6d095..b60277b44468 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c | |||
| @@ -141,7 +141,7 @@ static void nilfs_check_page(struct page *page) | |||
| 141 | } | 141 | } |
| 142 | for (offs = 0; offs <= limit - NILFS_DIR_REC_LEN(1); offs += rec_len) { | 142 | for (offs = 0; offs <= limit - NILFS_DIR_REC_LEN(1); offs += rec_len) { |
| 143 | p = (struct nilfs_dir_entry *)(kaddr + offs); | 143 | p = (struct nilfs_dir_entry *)(kaddr + offs); |
| 144 | rec_len = le16_to_cpu(p->rec_len); | 144 | rec_len = nilfs_rec_len_from_disk(p->rec_len); |
| 145 | 145 | ||
| 146 | if (rec_len < NILFS_DIR_REC_LEN(1)) | 146 | if (rec_len < NILFS_DIR_REC_LEN(1)) |
| 147 | goto Eshort; | 147 | goto Eshort; |
| @@ -235,7 +235,8 @@ nilfs_match(int len, const unsigned char *name, struct nilfs_dir_entry *de) | |||
| 235 | */ | 235 | */ |
| 236 | static struct nilfs_dir_entry *nilfs_next_entry(struct nilfs_dir_entry *p) | 236 | static struct nilfs_dir_entry *nilfs_next_entry(struct nilfs_dir_entry *p) |
| 237 | { | 237 | { |
| 238 | return (struct nilfs_dir_entry *)((char *)p + le16_to_cpu(p->rec_len)); | 238 | return (struct nilfs_dir_entry *)((char *)p + |
| 239 | nilfs_rec_len_from_disk(p->rec_len)); | ||
| 239 | } | 240 | } |
| 240 | 241 | ||
| 241 | static unsigned char | 242 | static unsigned char |
| @@ -326,7 +327,7 @@ static int nilfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 326 | goto success; | 327 | goto success; |
| 327 | } | 328 | } |
| 328 | } | 329 | } |
| 329 | filp->f_pos += le16_to_cpu(de->rec_len); | 330 | filp->f_pos += nilfs_rec_len_from_disk(de->rec_len); |
| 330 | } | 331 | } |
| 331 | nilfs_put_page(page); | 332 | nilfs_put_page(page); |
| 332 | } | 333 | } |
| @@ -441,7 +442,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de, | |||
| 441 | struct page *page, struct inode *inode) | 442 | struct page *page, struct inode *inode) |
| 442 | { | 443 | { |
| 443 | unsigned from = (char *) de - (char *) page_address(page); | 444 | unsigned from = (char *) de - (char *) page_address(page); |
| 444 | unsigned to = from + le16_to_cpu(de->rec_len); | 445 | unsigned to = from + nilfs_rec_len_from_disk(de->rec_len); |
| 445 | struct address_space *mapping = page->mapping; | 446 | struct address_space *mapping = page->mapping; |
| 446 | int err; | 447 | int err; |
| 447 | 448 | ||
| @@ -497,7 +498,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode) | |||
| 497 | /* We hit i_size */ | 498 | /* We hit i_size */ |
| 498 | name_len = 0; | 499 | name_len = 0; |
| 499 | rec_len = chunk_size; | 500 | rec_len = chunk_size; |
| 500 | de->rec_len = cpu_to_le16(chunk_size); | 501 | de->rec_len = nilfs_rec_len_to_disk(chunk_size); |
| 501 | de->inode = 0; | 502 | de->inode = 0; |
| 502 | goto got_it; | 503 | goto got_it; |
| 503 | } | 504 | } |
| @@ -511,7 +512,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode) | |||
| 511 | if (nilfs_match(namelen, name, de)) | 512 | if (nilfs_match(namelen, name, de)) |
| 512 | goto out_unlock; | 513 | goto out_unlock; |
| 513 | name_len = NILFS_DIR_REC_LEN(de->name_len); | 514 | name_len = NILFS_DIR_REC_LEN(de->name_len); |
| 514 | rec_len = le16_to_cpu(de->rec_len); | 515 | rec_len = nilfs_rec_len_from_disk(de->rec_len); |
| 515 | if (!de->inode && rec_len >= reclen) | 516 | if (!de->inode && rec_len >= reclen) |
| 516 | goto got_it; | 517 | goto got_it; |
| 517 | if (rec_len >= name_len + reclen) | 518 | if (rec_len >= name_len + reclen) |
| @@ -534,8 +535,8 @@ got_it: | |||
| 534 | struct nilfs_dir_entry *de1; | 535 | struct nilfs_dir_entry *de1; |
| 535 | 536 | ||
| 536 | de1 = (struct nilfs_dir_entry *)((char *)de + name_len); | 537 | de1 = (struct nilfs_dir_entry *)((char *)de + name_len); |
| 537 | de1->rec_len = cpu_to_le16(rec_len - name_len); | 538 | de1->rec_len = nilfs_rec_len_to_disk(rec_len - name_len); |
| 538 | de->rec_len = cpu_to_le16(name_len); | 539 | de->rec_len = nilfs_rec_len_to_disk(name_len); |
| 539 | de = de1; | 540 | de = de1; |
| 540 | } | 541 | } |
| 541 | de->name_len = namelen; | 542 | de->name_len = namelen; |
| @@ -566,7 +567,8 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page) | |||
| 566 | struct inode *inode = mapping->host; | 567 | struct inode *inode = mapping->host; |
| 567 | char *kaddr = page_address(page); | 568 | char *kaddr = page_address(page); |
| 568 | unsigned from = ((char *)dir - kaddr) & ~(nilfs_chunk_size(inode) - 1); | 569 | unsigned from = ((char *)dir - kaddr) & ~(nilfs_chunk_size(inode) - 1); |
| 569 | unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len); | 570 | unsigned to = ((char *)dir - kaddr) + |
| 571 | nilfs_rec_len_from_disk(dir->rec_len); | ||
| 570 | struct nilfs_dir_entry *pde = NULL; | 572 | struct nilfs_dir_entry *pde = NULL; |
| 571 | struct nilfs_dir_entry *de = (struct nilfs_dir_entry *)(kaddr + from); | 573 | struct nilfs_dir_entry *de = (struct nilfs_dir_entry *)(kaddr + from); |
| 572 | int err; | 574 | int err; |
| @@ -587,7 +589,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page) | |||
| 587 | err = nilfs_prepare_chunk(page, mapping, from, to); | 589 | err = nilfs_prepare_chunk(page, mapping, from, to); |
| 588 | BUG_ON(err); | 590 | BUG_ON(err); |
| 589 | if (pde) | 591 | if (pde) |
| 590 | pde->rec_len = cpu_to_le16(to - from); | 592 | pde->rec_len = nilfs_rec_len_to_disk(to - from); |
| 591 | dir->inode = 0; | 593 | dir->inode = 0; |
| 592 | nilfs_commit_chunk(page, mapping, from, to); | 594 | nilfs_commit_chunk(page, mapping, from, to); |
| 593 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; | 595 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; |
| @@ -621,14 +623,14 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent) | |||
| 621 | memset(kaddr, 0, chunk_size); | 623 | memset(kaddr, 0, chunk_size); |
| 622 | de = (struct nilfs_dir_entry *)kaddr; | 624 | de = (struct nilfs_dir_entry *)kaddr; |
| 623 | de->name_len = 1; | 625 | de->name_len = 1; |
| 624 | de->rec_len = cpu_to_le16(NILFS_DIR_REC_LEN(1)); | 626 | de->rec_len = nilfs_rec_len_to_disk(NILFS_DIR_REC_LEN(1)); |
| 625 | memcpy(de->name, ".\0\0", 4); | 627 | memcpy(de->name, ".\0\0", 4); |
| 626 | de->inode = cpu_to_le64(inode->i_ino); | 628 | de->inode = cpu_to_le64(inode->i_ino); |
| 627 | nilfs_set_de_type(de, inode); | 629 | nilfs_set_de_type(de, inode); |
| 628 | 630 | ||
| 629 | de = (struct nilfs_dir_entry *)(kaddr + NILFS_DIR_REC_LEN(1)); | 631 | de = (struct nilfs_dir_entry *)(kaddr + NILFS_DIR_REC_LEN(1)); |
| 630 | de->name_len = 2; | 632 | de->name_len = 2; |
| 631 | de->rec_len = cpu_to_le16(chunk_size - NILFS_DIR_REC_LEN(1)); | 633 | de->rec_len = nilfs_rec_len_to_disk(chunk_size - NILFS_DIR_REC_LEN(1)); |
| 632 | de->inode = cpu_to_le64(parent->i_ino); | 634 | de->inode = cpu_to_le64(parent->i_ino); |
| 633 | memcpy(de->name, "..\0", 4); | 635 | memcpy(de->name, "..\0", 4); |
| 634 | nilfs_set_de_type(de, inode); | 636 | nilfs_set_de_type(de, inode); |
diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h index 7dd4cd494490..970828a5ffc5 100644 --- a/include/linux/nilfs2_fs.h +++ b/include/linux/nilfs2_fs.h | |||
| @@ -326,7 +326,25 @@ enum { | |||
| 326 | #define NILFS_DIR_ROUND (NILFS_DIR_PAD - 1) | 326 | #define NILFS_DIR_ROUND (NILFS_DIR_PAD - 1) |
| 327 | #define NILFS_DIR_REC_LEN(name_len) (((name_len) + 12 + NILFS_DIR_ROUND) & \ | 327 | #define NILFS_DIR_REC_LEN(name_len) (((name_len) + 12 + NILFS_DIR_ROUND) & \ |
| 328 | ~NILFS_DIR_ROUND) | 328 | ~NILFS_DIR_ROUND) |
| 329 | #define NILFS_MAX_REC_LEN ((1<<16)-1) | ||
| 329 | 330 | ||
| 331 | static inline unsigned nilfs_rec_len_from_disk(__le16 dlen) | ||
| 332 | { | ||
| 333 | unsigned len = le16_to_cpu(dlen); | ||
| 334 | |||
| 335 | if (len == NILFS_MAX_REC_LEN) | ||
| 336 | return 1 << 16; | ||
| 337 | return len; | ||
| 338 | } | ||
| 339 | |||
| 340 | static inline __le16 nilfs_rec_len_to_disk(unsigned len) | ||
| 341 | { | ||
| 342 | if (len == (1 << 16)) | ||
| 343 | return cpu_to_le16(NILFS_MAX_REC_LEN); | ||
| 344 | else if (len > (1 << 16)) | ||
| 345 | BUG(); | ||
| 346 | return cpu_to_le16(len); | ||
| 347 | } | ||
| 330 | 348 | ||
| 331 | /** | 349 | /** |
| 332 | * struct nilfs_finfo - file information | 350 | * struct nilfs_finfo - file information |
