1/* 2 * Copyright (C) 2005, 2006 3 * Avishay Traeger (avishay@gmail.com) 4 * Copyright (C) 2008, 2009 5 * Boaz Harrosh <ooo@electrozaur.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 *file, struct dir_context *ctx) 243{ 244 loff_t pos = ctx->pos; 245 struct inode *inode = file_inode(file); 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 int need_revalidate = (file->f_version != inode->i_version); 251 252 if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1)) 253 return 0; 254 255 for ( ; n < npages; n++, offset = 0) { 256 char *kaddr, *limit; 257 struct exofs_dir_entry *de; 258 struct page *page = exofs_get_page(inode, n); 259 260 if (IS_ERR(page)) { 261 EXOFS_ERR("ERROR: bad page in directory(0x%lx)\n", 262 inode->i_ino); 263 ctx->pos += PAGE_CACHE_SIZE - offset; 264 return PTR_ERR(page); 265 } 266 kaddr = page_address(page); 267 if (unlikely(need_revalidate)) { 268 if (offset) { 269 offset = exofs_validate_entry(kaddr, offset, 270 chunk_mask); 271 ctx->pos = (n<<PAGE_CACHE_SHIFT) + offset; 272 } 273 file->f_version = inode->i_version; 274 need_revalidate = 0; 275 } 276 de = (struct exofs_dir_entry *)(kaddr + offset); 277 limit = kaddr + exofs_last_byte(inode, n) - 278 EXOFS_DIR_REC_LEN(1); 279 for (; (char *)de <= limit; de = exofs_next_entry(de)) { 280 if (de->rec_len == 0) { 281 EXOFS_ERR("ERROR: " 282 "zero-length entry in directory(0x%lx)\n", 283 inode->i_ino); 284 exofs_put_page(page); 285 return -EIO; 286 } 287 if (de->inode_no) { 288 unsigned char t; 289 290 if (de->file_type < EXOFS_FT_MAX) 291 t = exofs_filetype_table[de->file_type]; 292 else 293 t = DT_UNKNOWN; 294 295 if (!dir_emit(ctx, de->name, de->name_len, 296 le64_to_cpu(de->inode_no), 297 t)) { 298 exofs_put_page(page); 299 return 0; 300 } 301 } 302 ctx->pos += le16_to_cpu(de->rec_len); 303 } 304 exofs_put_page(page); 305 } 306 return 0; 307} 308 309struct exofs_dir_entry *exofs_find_entry(struct inode *dir, 310 struct dentry *dentry, struct page **res_page) 311{ 312 const unsigned char *name = dentry->d_name.name; 313 int namelen = dentry->d_name.len; 314 unsigned reclen = EXOFS_DIR_REC_LEN(namelen); 315 unsigned long start, n; 316 unsigned long npages = dir_pages(dir); 317 struct page *page = NULL; 318 struct exofs_i_info *oi = exofs_i(dir); 319 struct exofs_dir_entry *de; 320 321 if (npages == 0) 322 goto out; 323 324 *res_page = NULL; 325 326 start = oi->i_dir_start_lookup; 327 if (start >= npages) 328 start = 0; 329 n = start; 330 do { 331 char *kaddr; 332 page = exofs_get_page(dir, n); 333 if (!IS_ERR(page)) { 334 kaddr = page_address(page); 335 de = (struct exofs_dir_entry *) kaddr; 336 kaddr += exofs_last_byte(dir, n) - reclen; 337 while ((char *) de <= kaddr) { 338 if (de->rec_len == 0) { 339 EXOFS_ERR("ERROR: zero-length entry in " 340 "directory(0x%lx)\n", 341 dir->i_ino); 342 exofs_put_page(page); 343 goto out; 344 } 345 if (exofs_match(namelen, name, de)) 346 goto found; 347 de = exofs_next_entry(de); 348 } 349 exofs_put_page(page); 350 } 351 if (++n >= npages) 352 n = 0; 353 } while (n != start); 354out: 355 return NULL; 356 357found: 358 *res_page = page; 359 oi->i_dir_start_lookup = n; 360 return de; 361} 362 363struct exofs_dir_entry *exofs_dotdot(struct inode *dir, struct page **p) 364{ 365 struct page *page = exofs_get_page(dir, 0); 366 struct exofs_dir_entry *de = NULL; 367 368 if (!IS_ERR(page)) { 369 de = exofs_next_entry( 370 (struct exofs_dir_entry *)page_address(page)); 371 *p = page; 372 } 373 return de; 374} 375 376ino_t exofs_parent_ino(struct dentry *child) 377{ 378 struct page *page; 379 struct exofs_dir_entry *de; 380 ino_t ino; 381 382 de = exofs_dotdot(d_inode(child), &page); 383 if (!de) 384 return 0; 385 386 ino = le64_to_cpu(de->inode_no); 387 exofs_put_page(page); 388 return ino; 389} 390 391ino_t exofs_inode_by_name(struct inode *dir, struct dentry *dentry) 392{ 393 ino_t res = 0; 394 struct exofs_dir_entry *de; 395 struct page *page; 396 397 de = exofs_find_entry(dir, dentry, &page); 398 if (de) { 399 res = le64_to_cpu(de->inode_no); 400 exofs_put_page(page); 401 } 402 return res; 403} 404 405int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de, 406 struct page *page, struct inode *inode) 407{ 408 loff_t pos = page_offset(page) + 409 (char *) de - (char *) page_address(page); 410 unsigned len = le16_to_cpu(de->rec_len); 411 int err; 412 413 lock_page(page); 414 err = exofs_write_begin(NULL, page->mapping, pos, len, 415 AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); 416 if (err) 417 EXOFS_ERR("exofs_set_link: exofs_write_begin FAILED => %d\n", 418 err); 419 420 de->inode_no = cpu_to_le64(inode->i_ino); 421 exofs_set_de_type(de, inode); 422 if (likely(!err)) 423 err = exofs_commit_chunk(page, pos, len); 424 exofs_put_page(page); 425 dir->i_mtime = dir->i_ctime = CURRENT_TIME; 426 mark_inode_dirty(dir); 427 return err; 428} 429 430int exofs_add_link(struct dentry *dentry, struct inode *inode) 431{ 432 struct inode *dir = d_inode(dentry->d_parent); 433 const unsigned char *name = dentry->d_name.name; 434 int namelen = dentry->d_name.len; 435 unsigned chunk_size = exofs_chunk_size(dir); 436 unsigned reclen = EXOFS_DIR_REC_LEN(namelen); 437 unsigned short rec_len, name_len; 438 struct page *page = NULL; 439 struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; 440 struct exofs_dir_entry *de; 441 unsigned long npages = dir_pages(dir); 442 unsigned long n; 443 char *kaddr; 444 loff_t pos; 445 int err; 446 447 for (n = 0; n <= npages; n++) { 448 char *dir_end; 449 450 page = exofs_get_page(dir, n); 451 err = PTR_ERR(page); 452 if (IS_ERR(page)) 453 goto out; 454 lock_page(page); 455 kaddr = page_address(page); 456 dir_end = kaddr + exofs_last_byte(dir, n); 457 de = (struct exofs_dir_entry *)kaddr; 458 kaddr += PAGE_CACHE_SIZE - reclen; 459 while ((char *)de <= kaddr) { 460 if ((char *)de == dir_end) { 461 name_len = 0; 462 rec_len = chunk_size; 463 de->rec_len = cpu_to_le16(chunk_size); 464 de->inode_no = 0; 465 goto got_it; 466 } 467 if (de->rec_len == 0) { 468 EXOFS_ERR("ERROR: exofs_add_link: " 469 "zero-length entry in directory(0x%lx)\n", 470 inode->i_ino); 471 err = -EIO; 472 goto out_unlock; 473 } 474 err = -EEXIST; 475 if (exofs_match(namelen, name, de)) 476 goto out_unlock; 477 name_len = EXOFS_DIR_REC_LEN(de->name_len); 478 rec_len = le16_to_cpu(de->rec_len); 479 if (!de->inode_no && rec_len >= reclen) 480 goto got_it; 481 if (rec_len >= name_len + reclen) 482 goto got_it; 483 de = (struct exofs_dir_entry *) ((char *) de + rec_len); 484 } 485 unlock_page(page); 486 exofs_put_page(page); 487 } 488 489 EXOFS_ERR("exofs_add_link: BAD dentry=%p or inode=0x%lx\n", 490 dentry, inode->i_ino); 491 return -EINVAL; 492 493got_it: 494 pos = page_offset(page) + 495 (char *)de - (char *)page_address(page); 496 err = exofs_write_begin(NULL, page->mapping, pos, rec_len, 0, 497 &page, NULL); 498 if (err) 499 goto out_unlock; 500 if (de->inode_no) { 501 struct exofs_dir_entry *de1 = 502 (struct exofs_dir_entry *)((char *)de + name_len); 503 de1->rec_len = cpu_to_le16(rec_len - name_len); 504 de->rec_len = cpu_to_le16(name_len); 505 de = de1; 506 } 507 de->name_len = namelen; 508 memcpy(de->name, name, namelen); 509 de->inode_no = cpu_to_le64(inode->i_ino); 510 exofs_set_de_type(de, inode); 511 err = exofs_commit_chunk(page, pos, rec_len); 512 dir->i_mtime = dir->i_ctime = CURRENT_TIME; 513 mark_inode_dirty(dir); 514 sbi->s_numfiles++; 515 516out_put: 517 exofs_put_page(page); 518out: 519 return err; 520out_unlock: 521 unlock_page(page); 522 goto out_put; 523} 524 525int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page) 526{ 527 struct address_space *mapping = page->mapping; 528 struct inode *inode = mapping->host; 529 struct exofs_sb_info *sbi = inode->i_sb->s_fs_info; 530 char *kaddr = page_address(page); 531 unsigned from = ((char *)dir - kaddr) & ~(exofs_chunk_size(inode)-1); 532 unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len); 533 loff_t pos; 534 struct exofs_dir_entry *pde = NULL; 535 struct exofs_dir_entry *de = (struct exofs_dir_entry *) (kaddr + from); 536 int err; 537 538 while (de < dir) { 539 if (de->rec_len == 0) { 540 EXOFS_ERR("ERROR: exofs_delete_entry:" 541 "zero-length entry in directory(0x%lx)\n", 542 inode->i_ino); 543 err = -EIO; 544 goto out; 545 } 546 pde = de; 547 de = exofs_next_entry(de); 548 } 549 if (pde) 550 from = (char *)pde - (char *)page_address(page); 551 pos = page_offset(page) + from; 552 lock_page(page); 553 err = exofs_write_begin(NULL, page->mapping, pos, to - from, 0, 554 &page, NULL); 555 if (err) 556 EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILED => %d\n", 557 err); 558 if (pde) 559 pde->rec_len = cpu_to_le16(to - from); 560 dir->inode_no = 0; 561 if (likely(!err)) 562 err = exofs_commit_chunk(page, pos, to - from); 563 inode->i_ctime = inode->i_mtime = CURRENT_TIME; 564 mark_inode_dirty(inode); 565 sbi->s_numfiles--; 566out: 567 exofs_put_page(page); 568 return err; 569} 570 571/* kept aligned on 4 bytes */ 572#define THIS_DIR ".\0\0" 573#define PARENT_DIR "..\0" 574 575int exofs_make_empty(struct inode *inode, struct inode *parent) 576{ 577 struct address_space *mapping = inode->i_mapping; 578 struct page *page = grab_cache_page(mapping, 0); 579 unsigned chunk_size = exofs_chunk_size(inode); 580 struct exofs_dir_entry *de; 581 int err; 582 void *kaddr; 583 584 if (!page) 585 return -ENOMEM; 586 587 err = exofs_write_begin(NULL, page->mapping, 0, chunk_size, 0, 588 &page, NULL); 589 if (err) { 590 unlock_page(page); 591 goto fail; 592 } 593 594 kaddr = kmap_atomic(page); 595 de = (struct exofs_dir_entry *)kaddr; 596 de->name_len = 1; 597 de->rec_len = cpu_to_le16(EXOFS_DIR_REC_LEN(1)); 598 memcpy(de->name, THIS_DIR, sizeof(THIS_DIR)); 599 de->inode_no = cpu_to_le64(inode->i_ino); 600 exofs_set_de_type(de, inode); 601 602 de = (struct exofs_dir_entry *)(kaddr + EXOFS_DIR_REC_LEN(1)); 603 de->name_len = 2; 604 de->rec_len = cpu_to_le16(chunk_size - EXOFS_DIR_REC_LEN(1)); 605 de->inode_no = cpu_to_le64(parent->i_ino); 606 memcpy(de->name, PARENT_DIR, sizeof(PARENT_DIR)); 607 exofs_set_de_type(de, inode); 608 kunmap_atomic(kaddr); 609 err = exofs_commit_chunk(page, 0, chunk_size); 610fail: 611 page_cache_release(page); 612 return err; 613} 614 615int exofs_empty_dir(struct inode *inode) 616{ 617 struct page *page = NULL; 618 unsigned long i, npages = dir_pages(inode); 619 620 for (i = 0; i < npages; i++) { 621 char *kaddr; 622 struct exofs_dir_entry *de; 623 page = exofs_get_page(inode, i); 624 625 if (IS_ERR(page)) 626 continue; 627 628 kaddr = page_address(page); 629 de = (struct exofs_dir_entry *)kaddr; 630 kaddr += exofs_last_byte(inode, i) - EXOFS_DIR_REC_LEN(1); 631 632 while ((char *)de <= kaddr) { 633 if (de->rec_len == 0) { 634 EXOFS_ERR("ERROR: exofs_empty_dir: " 635 "zero-length directory entry" 636 "kaddr=%p, de=%p\n", kaddr, de); 637 goto not_empty; 638 } 639 if (de->inode_no != 0) { 640 /* check for . and .. */ 641 if (de->name[0] != '.') 642 goto not_empty; 643 if (de->name_len > 2) 644 goto not_empty; 645 if (de->name_len < 2) { 646 if (le64_to_cpu(de->inode_no) != 647 inode->i_ino) 648 goto not_empty; 649 } else if (de->name[1] != '.') 650 goto not_empty; 651 } 652 de = exofs_next_entry(de); 653 } 654 exofs_put_page(page); 655 } 656 return 1; 657 658not_empty: 659 exofs_put_page(page); 660 return 0; 661} 662 663const struct file_operations exofs_dir_operations = { 664 .llseek = generic_file_llseek, 665 .read = generic_read_dir, 666 .iterate = exofs_readdir, 667}; 668