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