at v3.9 673 lines 17 kB view raw
1/* 2 * Copyright (C) 2005, 2006 3 * Avishay Traeger (avishay@gmail.com) 4 * Copyright (C) 2008, 2009 5 * Boaz Harrosh <bharrosh@panasas.com> 6 * 7 * Copyrights for code taken from ext2: 8 * Copyright (C) 1992, 1993, 1994, 1995 9 * Remy Card (card@masi.ibp.fr) 10 * Laboratoire MASI - Institut Blaise Pascal 11 * Universite Pierre et Marie Curie (Paris VI) 12 * from 13 * linux/fs/minix/inode.c 14 * Copyright (C) 1991, 1992 Linus Torvalds 15 * 16 * This file is part of exofs. 17 * 18 * exofs is free software; you can redistribute it and/or modify 19 * it under the terms of the GNU General Public License as published by 20 * the Free Software Foundation. Since it is based on ext2, and the only 21 * valid version of GPL for the Linux kernel is version 2, the only valid 22 * version of GPL for exofs is version 2. 23 * 24 * exofs is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License 30 * along with exofs; if not, write to the Free Software 31 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 32 */ 33 34#include "exofs.h" 35 36static inline unsigned exofs_chunk_size(struct inode *inode) 37{ 38 return inode->i_sb->s_blocksize; 39} 40 41static inline void exofs_put_page(struct page *page) 42{ 43 kunmap(page); 44 page_cache_release(page); 45} 46 47/* Accesses dir's inode->i_size must be called under inode lock */ 48static inline unsigned long dir_pages(struct inode *inode) 49{ 50 return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 51} 52 53static unsigned exofs_last_byte(struct inode *inode, unsigned long page_nr) 54{ 55 loff_t last_byte = inode->i_size; 56 57 last_byte -= page_nr << PAGE_CACHE_SHIFT; 58 if (last_byte > PAGE_CACHE_SIZE) 59 last_byte = PAGE_CACHE_SIZE; 60 return last_byte; 61} 62 63static int exofs_commit_chunk(struct page *page, loff_t pos, unsigned len) 64{ 65 struct address_space *mapping = page->mapping; 66 struct inode *dir = mapping->host; 67 int err = 0; 68 69 dir->i_version++; 70 71 if (!PageUptodate(page)) 72 SetPageUptodate(page); 73 74 if (pos+len > dir->i_size) { 75 i_size_write(dir, pos+len); 76 mark_inode_dirty(dir); 77 } 78 set_page_dirty(page); 79 80 if (IS_DIRSYNC(dir)) 81 err = write_one_page(page, 1); 82 else 83 unlock_page(page); 84 85 return err; 86} 87 88static void exofs_check_page(struct page *page) 89{ 90 struct inode *dir = page->mapping->host; 91 unsigned chunk_size = exofs_chunk_size(dir); 92 char *kaddr = page_address(page); 93 unsigned offs, rec_len; 94 unsigned limit = PAGE_CACHE_SIZE; 95 struct exofs_dir_entry *p; 96 char *error; 97 98 /* if the page is the last one in the directory */ 99 if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) { 100 limit = dir->i_size & ~PAGE_CACHE_MASK; 101 if (limit & (chunk_size - 1)) 102 goto Ebadsize; 103 if (!limit) 104 goto out; 105 } 106 for (offs = 0; offs <= limit - EXOFS_DIR_REC_LEN(1); offs += rec_len) { 107 p = (struct exofs_dir_entry *)(kaddr + offs); 108 rec_len = le16_to_cpu(p->rec_len); 109 110 if (rec_len < EXOFS_DIR_REC_LEN(1)) 111 goto Eshort; 112 if (rec_len & 3) 113 goto Ealign; 114 if (rec_len < EXOFS_DIR_REC_LEN(p->name_len)) 115 goto Enamelen; 116 if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1)) 117 goto Espan; 118 } 119 if (offs != limit) 120 goto Eend; 121out: 122 SetPageChecked(page); 123 return; 124 125Ebadsize: 126 EXOFS_ERR("ERROR [exofs_check_page]: " 127 "size of directory(0x%lx) is not a multiple of chunk size\n", 128 dir->i_ino 129 ); 130 goto fail; 131Eshort: 132 error = "rec_len is smaller than minimal"; 133 goto bad_entry; 134Ealign: 135 error = "unaligned directory entry"; 136 goto bad_entry; 137Enamelen: 138 error = "rec_len is too small for name_len"; 139 goto bad_entry; 140Espan: 141 error = "directory entry across blocks"; 142 goto bad_entry; 143bad_entry: 144 EXOFS_ERR( 145 "ERROR [exofs_check_page]: bad entry in directory(0x%lx): %s - " 146 "offset=%lu, inode=0x%llu, rec_len=%d, name_len=%d\n", 147 dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs, 148 _LLU(le64_to_cpu(p->inode_no)), 149 rec_len, p->name_len); 150 goto fail; 151Eend: 152 p = (struct exofs_dir_entry *)(kaddr + offs); 153 EXOFS_ERR("ERROR [exofs_check_page]: " 154 "entry in directory(0x%lx) spans the page boundary" 155 "offset=%lu, inode=0x%llx\n", 156 dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs, 157 _LLU(le64_to_cpu(p->inode_no))); 158fail: 159 SetPageChecked(page); 160 SetPageError(page); 161} 162 163static struct page *exofs_get_page(struct inode *dir, unsigned long n) 164{ 165 struct address_space *mapping = dir->i_mapping; 166 struct page *page = read_mapping_page(mapping, n, NULL); 167 168 if (!IS_ERR(page)) { 169 kmap(page); 170 if (!PageChecked(page)) 171 exofs_check_page(page); 172 if (PageError(page)) 173 goto fail; 174 } 175 return page; 176 177fail: 178 exofs_put_page(page); 179 return ERR_PTR(-EIO); 180} 181 182static inline int exofs_match(int len, const unsigned char *name, 183 struct exofs_dir_entry *de) 184{ 185 if (len != de->name_len) 186 return 0; 187 if (!de->inode_no) 188 return 0; 189 return !memcmp(name, de->name, len); 190} 191 192static inline 193struct exofs_dir_entry *exofs_next_entry(struct exofs_dir_entry *p) 194{ 195 return (struct exofs_dir_entry *)((char *)p + le16_to_cpu(p->rec_len)); 196} 197 198static inline unsigned 199exofs_validate_entry(char *base, unsigned offset, unsigned mask) 200{ 201 struct exofs_dir_entry *de = (struct exofs_dir_entry *)(base + offset); 202 struct exofs_dir_entry *p = 203 (struct exofs_dir_entry *)(base + (offset&mask)); 204 while ((char *)p < (char *)de) { 205 if (p->rec_len == 0) 206 break; 207 p = exofs_next_entry(p); 208 } 209 return (char *)p - base; 210} 211 212static unsigned char exofs_filetype_table[EXOFS_FT_MAX] = { 213 [EXOFS_FT_UNKNOWN] = DT_UNKNOWN, 214 [EXOFS_FT_REG_FILE] = DT_REG, 215 [EXOFS_FT_DIR] = DT_DIR, 216 [EXOFS_FT_CHRDEV] = DT_CHR, 217 [EXOFS_FT_BLKDEV] = DT_BLK, 218 [EXOFS_FT_FIFO] = DT_FIFO, 219 [EXOFS_FT_SOCK] = DT_SOCK, 220 [EXOFS_FT_SYMLINK] = DT_LNK, 221}; 222 223#define S_SHIFT 12 224static unsigned char exofs_type_by_mode[S_IFMT >> S_SHIFT] = { 225 [S_IFREG >> S_SHIFT] = EXOFS_FT_REG_FILE, 226 [S_IFDIR >> S_SHIFT] = EXOFS_FT_DIR, 227 [S_IFCHR >> S_SHIFT] = EXOFS_FT_CHRDEV, 228 [S_IFBLK >> S_SHIFT] = EXOFS_FT_BLKDEV, 229 [S_IFIFO >> S_SHIFT] = EXOFS_FT_FIFO, 230 [S_IFSOCK >> S_SHIFT] = EXOFS_FT_SOCK, 231 [S_IFLNK >> S_SHIFT] = EXOFS_FT_SYMLINK, 232}; 233 234static inline 235void exofs_set_de_type(struct exofs_dir_entry *de, struct inode *inode) 236{ 237 umode_t mode = inode->i_mode; 238 de->file_type = exofs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; 239} 240 241static int 242exofs_readdir(struct file *filp, void *dirent, filldir_t filldir) 243{ 244 loff_t pos = filp->f_pos; 245 struct inode *inode = file_inode(filp); 246 unsigned int offset = pos & ~PAGE_CACHE_MASK; 247 unsigned long n = pos >> PAGE_CACHE_SHIFT; 248 unsigned long npages = dir_pages(inode); 249 unsigned chunk_mask = ~(exofs_chunk_size(inode)-1); 250 unsigned char *types = NULL; 251 int need_revalidate = (filp->f_version != inode->i_version); 252 253 if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1)) 254 return 0; 255 256 types = exofs_filetype_table; 257 258 for ( ; n < npages; n++, offset = 0) { 259 char *kaddr, *limit; 260 struct exofs_dir_entry *de; 261 struct page *page = exofs_get_page(inode, n); 262 263 if (IS_ERR(page)) { 264 EXOFS_ERR("ERROR: bad page in directory(0x%lx)\n", 265 inode->i_ino); 266 filp->f_pos += PAGE_CACHE_SIZE - offset; 267 return PTR_ERR(page); 268 } 269 kaddr = page_address(page); 270 if (unlikely(need_revalidate)) { 271 if (offset) { 272 offset = exofs_validate_entry(kaddr, offset, 273 chunk_mask); 274 filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset; 275 } 276 filp->f_version = inode->i_version; 277 need_revalidate = 0; 278 } 279 de = (struct exofs_dir_entry *)(kaddr + offset); 280 limit = kaddr + exofs_last_byte(inode, n) - 281 EXOFS_DIR_REC_LEN(1); 282 for (; (char *)de <= limit; de = exofs_next_entry(de)) { 283 if (de->rec_len == 0) { 284 EXOFS_ERR("ERROR: " 285 "zero-length entry in directory(0x%lx)\n", 286 inode->i_ino); 287 exofs_put_page(page); 288 return -EIO; 289 } 290 if (de->inode_no) { 291 int over; 292 unsigned char d_type = DT_UNKNOWN; 293 294 if (types && de->file_type < EXOFS_FT_MAX) 295 d_type = types[de->file_type]; 296 297 offset = (char *)de - kaddr; 298 over = filldir(dirent, de->name, de->name_len, 299 (n<<PAGE_CACHE_SHIFT) | offset, 300 le64_to_cpu(de->inode_no), 301 d_type); 302 if (over) { 303 exofs_put_page(page); 304 return 0; 305 } 306 } 307 filp->f_pos += le16_to_cpu(de->rec_len); 308 } 309 exofs_put_page(page); 310 } 311 312 return 0; 313} 314 315struct exofs_dir_entry *exofs_find_entry(struct inode *dir, 316 struct dentry *dentry, struct page **res_page) 317{ 318 const unsigned char *name = dentry->d_name.name; 319 int namelen = dentry->d_name.len; 320 unsigned reclen = EXOFS_DIR_REC_LEN(namelen); 321 unsigned long start, n; 322 unsigned long npages = dir_pages(dir); 323 struct page *page = NULL; 324 struct exofs_i_info *oi = exofs_i(dir); 325 struct exofs_dir_entry *de; 326 327 if (npages == 0) 328 goto out; 329 330 *res_page = NULL; 331 332 start = oi->i_dir_start_lookup; 333 if (start >= npages) 334 start = 0; 335 n = start; 336 do { 337 char *kaddr; 338 page = exofs_get_page(dir, n); 339 if (!IS_ERR(page)) { 340 kaddr = page_address(page); 341 de = (struct exofs_dir_entry *) kaddr; 342 kaddr += exofs_last_byte(dir, n) - reclen; 343 while ((char *) de <= kaddr) { 344 if (de->rec_len == 0) { 345 EXOFS_ERR("ERROR: zero-length entry in " 346 "directory(0x%lx)\n", 347 dir->i_ino); 348 exofs_put_page(page); 349 goto out; 350 } 351 if (exofs_match(namelen, name, de)) 352 goto found; 353 de = exofs_next_entry(de); 354 } 355 exofs_put_page(page); 356 } 357 if (++n >= npages) 358 n = 0; 359 } while (n != start); 360out: 361 return NULL; 362 363found: 364 *res_page = page; 365 oi->i_dir_start_lookup = n; 366 return de; 367} 368 369struct exofs_dir_entry *exofs_dotdot(struct inode *dir, struct page **p) 370{ 371 struct page *page = exofs_get_page(dir, 0); 372 struct exofs_dir_entry *de = NULL; 373 374 if (!IS_ERR(page)) { 375 de = exofs_next_entry( 376 (struct exofs_dir_entry *)page_address(page)); 377 *p = page; 378 } 379 return de; 380} 381 382ino_t exofs_parent_ino(struct dentry *child) 383{ 384 struct page *page; 385 struct exofs_dir_entry *de; 386 ino_t ino; 387 388 de = exofs_dotdot(child->d_inode, &page); 389 if (!de) 390 return 0; 391 392 ino = le64_to_cpu(de->inode_no); 393 exofs_put_page(page); 394 return ino; 395} 396 397ino_t exofs_inode_by_name(struct inode *dir, struct dentry *dentry) 398{ 399 ino_t res = 0; 400 struct exofs_dir_entry *de; 401 struct page *page; 402 403 de = exofs_find_entry(dir, dentry, &page); 404 if (de) { 405 res = le64_to_cpu(de->inode_no); 406 exofs_put_page(page); 407 } 408 return res; 409} 410 411int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de, 412 struct page *page, struct inode *inode) 413{ 414 loff_t pos = page_offset(page) + 415 (char *) de - (char *) page_address(page); 416 unsigned len = le16_to_cpu(de->rec_len); 417 int err; 418 419 lock_page(page); 420 err = exofs_write_begin(NULL, page->mapping, pos, len, 421 AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); 422 if (err) 423 EXOFS_ERR("exofs_set_link: exofs_write_begin FAILED => %d\n", 424 err); 425 426 de->inode_no = cpu_to_le64(inode->i_ino); 427 exofs_set_de_type(de, inode); 428 if (likely(!err)) 429 err = exofs_commit_chunk(page, pos, len); 430 exofs_put_page(page); 431 dir->i_mtime = dir->i_ctime = CURRENT_TIME; 432 mark_inode_dirty(dir); 433 return err; 434} 435 436int exofs_add_link(struct dentry *dentry, struct inode *inode) 437{ 438 struct inode *dir = dentry->d_parent->d_inode; 439 const unsigned char *name = dentry->d_name.name; 440 int namelen = dentry->d_name.len; 441 unsigned chunk_size = exofs_chunk_size(dir); 442 unsigned reclen = EXOFS_DIR_REC_LEN(namelen); 443 unsigned short rec_len, name_len; 444 struct page *page = NULL; 445 struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; 446 struct exofs_dir_entry *de; 447 unsigned long npages = dir_pages(dir); 448 unsigned long n; 449 char *kaddr; 450 loff_t pos; 451 int err; 452 453 for (n = 0; n <= npages; n++) { 454 char *dir_end; 455 456 page = exofs_get_page(dir, n); 457 err = PTR_ERR(page); 458 if (IS_ERR(page)) 459 goto out; 460 lock_page(page); 461 kaddr = page_address(page); 462 dir_end = kaddr + exofs_last_byte(dir, n); 463 de = (struct exofs_dir_entry *)kaddr; 464 kaddr += PAGE_CACHE_SIZE - reclen; 465 while ((char *)de <= kaddr) { 466 if ((char *)de == dir_end) { 467 name_len = 0; 468 rec_len = chunk_size; 469 de->rec_len = cpu_to_le16(chunk_size); 470 de->inode_no = 0; 471 goto got_it; 472 } 473 if (de->rec_len == 0) { 474 EXOFS_ERR("ERROR: exofs_add_link: " 475 "zero-length entry in directory(0x%lx)\n", 476 inode->i_ino); 477 err = -EIO; 478 goto out_unlock; 479 } 480 err = -EEXIST; 481 if (exofs_match(namelen, name, de)) 482 goto out_unlock; 483 name_len = EXOFS_DIR_REC_LEN(de->name_len); 484 rec_len = le16_to_cpu(de->rec_len); 485 if (!de->inode_no && rec_len >= reclen) 486 goto got_it; 487 if (rec_len >= name_len + reclen) 488 goto got_it; 489 de = (struct exofs_dir_entry *) ((char *) de + rec_len); 490 } 491 unlock_page(page); 492 exofs_put_page(page); 493 } 494 495 EXOFS_ERR("exofs_add_link: BAD dentry=%p or inode=0x%lx\n", 496 dentry, inode->i_ino); 497 return -EINVAL; 498 499got_it: 500 pos = page_offset(page) + 501 (char *)de - (char *)page_address(page); 502 err = exofs_write_begin(NULL, page->mapping, pos, rec_len, 0, 503 &page, NULL); 504 if (err) 505 goto out_unlock; 506 if (de->inode_no) { 507 struct exofs_dir_entry *de1 = 508 (struct exofs_dir_entry *)((char *)de + name_len); 509 de1->rec_len = cpu_to_le16(rec_len - name_len); 510 de->rec_len = cpu_to_le16(name_len); 511 de = de1; 512 } 513 de->name_len = namelen; 514 memcpy(de->name, name, namelen); 515 de->inode_no = cpu_to_le64(inode->i_ino); 516 exofs_set_de_type(de, inode); 517 err = exofs_commit_chunk(page, pos, rec_len); 518 dir->i_mtime = dir->i_ctime = CURRENT_TIME; 519 mark_inode_dirty(dir); 520 sbi->s_numfiles++; 521 522out_put: 523 exofs_put_page(page); 524out: 525 return err; 526out_unlock: 527 unlock_page(page); 528 goto out_put; 529} 530 531int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page) 532{ 533 struct address_space *mapping = page->mapping; 534 struct inode *inode = mapping->host; 535 struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; 536 char *kaddr = page_address(page); 537 unsigned from = ((char *)dir - kaddr) & ~(exofs_chunk_size(inode)-1); 538 unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len); 539 loff_t pos; 540 struct exofs_dir_entry *pde = NULL; 541 struct exofs_dir_entry *de = (struct exofs_dir_entry *) (kaddr + from); 542 int err; 543 544 while (de < dir) { 545 if (de->rec_len == 0) { 546 EXOFS_ERR("ERROR: exofs_delete_entry:" 547 "zero-length entry in directory(0x%lx)\n", 548 inode->i_ino); 549 err = -EIO; 550 goto out; 551 } 552 pde = de; 553 de = exofs_next_entry(de); 554 } 555 if (pde) 556 from = (char *)pde - (char *)page_address(page); 557 pos = page_offset(page) + from; 558 lock_page(page); 559 err = exofs_write_begin(NULL, page->mapping, pos, to - from, 0, 560 &page, NULL); 561 if (err) 562 EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILED => %d\n", 563 err); 564 if (pde) 565 pde->rec_len = cpu_to_le16(to - from); 566 dir->inode_no = 0; 567 if (likely(!err)) 568 err = exofs_commit_chunk(page, pos, to - from); 569 inode->i_ctime = inode->i_mtime = CURRENT_TIME; 570 mark_inode_dirty(inode); 571 sbi->s_numfiles--; 572out: 573 exofs_put_page(page); 574 return err; 575} 576 577/* kept aligned on 4 bytes */ 578#define THIS_DIR ".\0\0" 579#define PARENT_DIR "..\0" 580 581int exofs_make_empty(struct inode *inode, struct inode *parent) 582{ 583 struct address_space *mapping = inode->i_mapping; 584 struct page *page = grab_cache_page(mapping, 0); 585 unsigned chunk_size = exofs_chunk_size(inode); 586 struct exofs_dir_entry *de; 587 int err; 588 void *kaddr; 589 590 if (!page) 591 return -ENOMEM; 592 593 err = exofs_write_begin(NULL, page->mapping, 0, chunk_size, 0, 594 &page, NULL); 595 if (err) { 596 unlock_page(page); 597 goto fail; 598 } 599 600 kaddr = kmap_atomic(page); 601 de = (struct exofs_dir_entry *)kaddr; 602 de->name_len = 1; 603 de->rec_len = cpu_to_le16(EXOFS_DIR_REC_LEN(1)); 604 memcpy(de->name, THIS_DIR, sizeof(THIS_DIR)); 605 de->inode_no = cpu_to_le64(inode->i_ino); 606 exofs_set_de_type(de, inode); 607 608 de = (struct exofs_dir_entry *)(kaddr + EXOFS_DIR_REC_LEN(1)); 609 de->name_len = 2; 610 de->rec_len = cpu_to_le16(chunk_size - EXOFS_DIR_REC_LEN(1)); 611 de->inode_no = cpu_to_le64(parent->i_ino); 612 memcpy(de->name, PARENT_DIR, sizeof(PARENT_DIR)); 613 exofs_set_de_type(de, inode); 614 kunmap_atomic(kaddr); 615 err = exofs_commit_chunk(page, 0, chunk_size); 616fail: 617 page_cache_release(page); 618 return err; 619} 620 621int exofs_empty_dir(struct inode *inode) 622{ 623 struct page *page = NULL; 624 unsigned long i, npages = dir_pages(inode); 625 626 for (i = 0; i < npages; i++) { 627 char *kaddr; 628 struct exofs_dir_entry *de; 629 page = exofs_get_page(inode, i); 630 631 if (IS_ERR(page)) 632 continue; 633 634 kaddr = page_address(page); 635 de = (struct exofs_dir_entry *)kaddr; 636 kaddr += exofs_last_byte(inode, i) - EXOFS_DIR_REC_LEN(1); 637 638 while ((char *)de <= kaddr) { 639 if (de->rec_len == 0) { 640 EXOFS_ERR("ERROR: exofs_empty_dir: " 641 "zero-length directory entry" 642 "kaddr=%p, de=%p\n", kaddr, de); 643 goto not_empty; 644 } 645 if (de->inode_no != 0) { 646 /* check for . and .. */ 647 if (de->name[0] != '.') 648 goto not_empty; 649 if (de->name_len > 2) 650 goto not_empty; 651 if (de->name_len < 2) { 652 if (le64_to_cpu(de->inode_no) != 653 inode->i_ino) 654 goto not_empty; 655 } else if (de->name[1] != '.') 656 goto not_empty; 657 } 658 de = exofs_next_entry(de); 659 } 660 exofs_put_page(page); 661 } 662 return 1; 663 664not_empty: 665 exofs_put_page(page); 666 return 0; 667} 668 669const struct file_operations exofs_dir_operations = { 670 .llseek = generic_file_llseek, 671 .read = generic_read_dir, 672 .readdir = exofs_readdir, 673};