at v5.0 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 <linux/iversion.h> 35#include "exofs.h" 36 37static inline unsigned exofs_chunk_size(struct inode *inode) 38{ 39 return inode->i_sb->s_blocksize; 40} 41 42static inline void exofs_put_page(struct page *page) 43{ 44 kunmap(page); 45 put_page(page); 46} 47 48static unsigned exofs_last_byte(struct inode *inode, unsigned long page_nr) 49{ 50 loff_t last_byte = inode->i_size; 51 52 last_byte -= page_nr << PAGE_SHIFT; 53 if (last_byte > PAGE_SIZE) 54 last_byte = PAGE_SIZE; 55 return last_byte; 56} 57 58static int exofs_commit_chunk(struct page *page, loff_t pos, unsigned len) 59{ 60 struct address_space *mapping = page->mapping; 61 struct inode *dir = mapping->host; 62 int err = 0; 63 64 inode_inc_iversion(dir); 65 66 if (!PageUptodate(page)) 67 SetPageUptodate(page); 68 69 if (pos+len > dir->i_size) { 70 i_size_write(dir, pos+len); 71 mark_inode_dirty(dir); 72 } 73 set_page_dirty(page); 74 75 if (IS_DIRSYNC(dir)) 76 err = write_one_page(page); 77 else 78 unlock_page(page); 79 80 return err; 81} 82 83static bool exofs_check_page(struct page *page) 84{ 85 struct inode *dir = page->mapping->host; 86 unsigned chunk_size = exofs_chunk_size(dir); 87 char *kaddr = page_address(page); 88 unsigned offs, rec_len; 89 unsigned limit = PAGE_SIZE; 90 struct exofs_dir_entry *p; 91 char *error; 92 93 /* if the page is the last one in the directory */ 94 if ((dir->i_size >> PAGE_SHIFT) == page->index) { 95 limit = dir->i_size & ~PAGE_MASK; 96 if (limit & (chunk_size - 1)) 97 goto Ebadsize; 98 if (!limit) 99 goto out; 100 } 101 for (offs = 0; offs <= limit - EXOFS_DIR_REC_LEN(1); offs += rec_len) { 102 p = (struct exofs_dir_entry *)(kaddr + offs); 103 rec_len = le16_to_cpu(p->rec_len); 104 105 if (rec_len < EXOFS_DIR_REC_LEN(1)) 106 goto Eshort; 107 if (rec_len & 3) 108 goto Ealign; 109 if (rec_len < EXOFS_DIR_REC_LEN(p->name_len)) 110 goto Enamelen; 111 if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1)) 112 goto Espan; 113 } 114 if (offs != limit) 115 goto Eend; 116out: 117 SetPageChecked(page); 118 return true; 119 120Ebadsize: 121 EXOFS_ERR("ERROR [exofs_check_page]: " 122 "size of directory(0x%lx) is not a multiple of chunk size\n", 123 dir->i_ino 124 ); 125 goto fail; 126Eshort: 127 error = "rec_len is smaller than minimal"; 128 goto bad_entry; 129Ealign: 130 error = "unaligned directory entry"; 131 goto bad_entry; 132Enamelen: 133 error = "rec_len is too small for name_len"; 134 goto bad_entry; 135Espan: 136 error = "directory entry across blocks"; 137 goto bad_entry; 138bad_entry: 139 EXOFS_ERR( 140 "ERROR [exofs_check_page]: bad entry in directory(0x%lx): %s - " 141 "offset=%lu, inode=0x%llx, rec_len=%d, name_len=%d\n", 142 dir->i_ino, error, (page->index<<PAGE_SHIFT)+offs, 143 _LLU(le64_to_cpu(p->inode_no)), 144 rec_len, p->name_len); 145 goto fail; 146Eend: 147 p = (struct exofs_dir_entry *)(kaddr + offs); 148 EXOFS_ERR("ERROR [exofs_check_page]: " 149 "entry in directory(0x%lx) spans the page boundary" 150 "offset=%lu, inode=0x%llx\n", 151 dir->i_ino, (page->index<<PAGE_SHIFT)+offs, 152 _LLU(le64_to_cpu(p->inode_no))); 153fail: 154 SetPageError(page); 155 return false; 156} 157 158static struct page *exofs_get_page(struct inode *dir, unsigned long n) 159{ 160 struct address_space *mapping = dir->i_mapping; 161 struct page *page = read_mapping_page(mapping, n, NULL); 162 163 if (!IS_ERR(page)) { 164 kmap(page); 165 if (unlikely(!PageChecked(page))) { 166 if (PageError(page) || !exofs_check_page(page)) 167 goto fail; 168 } 169 } 170 return page; 171 172fail: 173 exofs_put_page(page); 174 return ERR_PTR(-EIO); 175} 176 177static inline int exofs_match(int len, const unsigned char *name, 178 struct exofs_dir_entry *de) 179{ 180 if (len != de->name_len) 181 return 0; 182 if (!de->inode_no) 183 return 0; 184 return !memcmp(name, de->name, len); 185} 186 187static inline 188struct exofs_dir_entry *exofs_next_entry(struct exofs_dir_entry *p) 189{ 190 return (struct exofs_dir_entry *)((char *)p + le16_to_cpu(p->rec_len)); 191} 192 193static inline unsigned 194exofs_validate_entry(char *base, unsigned offset, unsigned mask) 195{ 196 struct exofs_dir_entry *de = (struct exofs_dir_entry *)(base + offset); 197 struct exofs_dir_entry *p = 198 (struct exofs_dir_entry *)(base + (offset&mask)); 199 while ((char *)p < (char *)de) { 200 if (p->rec_len == 0) 201 break; 202 p = exofs_next_entry(p); 203 } 204 return (char *)p - base; 205} 206 207static unsigned char exofs_filetype_table[EXOFS_FT_MAX] = { 208 [EXOFS_FT_UNKNOWN] = DT_UNKNOWN, 209 [EXOFS_FT_REG_FILE] = DT_REG, 210 [EXOFS_FT_DIR] = DT_DIR, 211 [EXOFS_FT_CHRDEV] = DT_CHR, 212 [EXOFS_FT_BLKDEV] = DT_BLK, 213 [EXOFS_FT_FIFO] = DT_FIFO, 214 [EXOFS_FT_SOCK] = DT_SOCK, 215 [EXOFS_FT_SYMLINK] = DT_LNK, 216}; 217 218#define S_SHIFT 12 219static unsigned char exofs_type_by_mode[S_IFMT >> S_SHIFT] = { 220 [S_IFREG >> S_SHIFT] = EXOFS_FT_REG_FILE, 221 [S_IFDIR >> S_SHIFT] = EXOFS_FT_DIR, 222 [S_IFCHR >> S_SHIFT] = EXOFS_FT_CHRDEV, 223 [S_IFBLK >> S_SHIFT] = EXOFS_FT_BLKDEV, 224 [S_IFIFO >> S_SHIFT] = EXOFS_FT_FIFO, 225 [S_IFSOCK >> S_SHIFT] = EXOFS_FT_SOCK, 226 [S_IFLNK >> S_SHIFT] = EXOFS_FT_SYMLINK, 227}; 228 229static inline 230void exofs_set_de_type(struct exofs_dir_entry *de, struct inode *inode) 231{ 232 umode_t mode = inode->i_mode; 233 de->file_type = exofs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; 234} 235 236static int 237exofs_readdir(struct file *file, struct dir_context *ctx) 238{ 239 loff_t pos = ctx->pos; 240 struct inode *inode = file_inode(file); 241 unsigned int offset = pos & ~PAGE_MASK; 242 unsigned long n = pos >> PAGE_SHIFT; 243 unsigned long npages = dir_pages(inode); 244 unsigned chunk_mask = ~(exofs_chunk_size(inode)-1); 245 bool need_revalidate = !inode_eq_iversion(inode, file->f_version); 246 247 if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1)) 248 return 0; 249 250 for ( ; n < npages; n++, offset = 0) { 251 char *kaddr, *limit; 252 struct exofs_dir_entry *de; 253 struct page *page = exofs_get_page(inode, n); 254 255 if (IS_ERR(page)) { 256 EXOFS_ERR("ERROR: bad page in directory(0x%lx)\n", 257 inode->i_ino); 258 ctx->pos += PAGE_SIZE - offset; 259 return PTR_ERR(page); 260 } 261 kaddr = page_address(page); 262 if (unlikely(need_revalidate)) { 263 if (offset) { 264 offset = exofs_validate_entry(kaddr, offset, 265 chunk_mask); 266 ctx->pos = (n<<PAGE_SHIFT) + offset; 267 } 268 file->f_version = inode_query_iversion(inode); 269 need_revalidate = false; 270 } 271 de = (struct exofs_dir_entry *)(kaddr + offset); 272 limit = kaddr + exofs_last_byte(inode, n) - 273 EXOFS_DIR_REC_LEN(1); 274 for (; (char *)de <= limit; de = exofs_next_entry(de)) { 275 if (de->rec_len == 0) { 276 EXOFS_ERR("ERROR: " 277 "zero-length entry in directory(0x%lx)\n", 278 inode->i_ino); 279 exofs_put_page(page); 280 return -EIO; 281 } 282 if (de->inode_no) { 283 unsigned char t; 284 285 if (de->file_type < EXOFS_FT_MAX) 286 t = exofs_filetype_table[de->file_type]; 287 else 288 t = DT_UNKNOWN; 289 290 if (!dir_emit(ctx, de->name, de->name_len, 291 le64_to_cpu(de->inode_no), 292 t)) { 293 exofs_put_page(page); 294 return 0; 295 } 296 } 297 ctx->pos += le16_to_cpu(de->rec_len); 298 } 299 exofs_put_page(page); 300 } 301 return 0; 302} 303 304struct exofs_dir_entry *exofs_find_entry(struct inode *dir, 305 struct dentry *dentry, struct page **res_page) 306{ 307 const unsigned char *name = dentry->d_name.name; 308 int namelen = dentry->d_name.len; 309 unsigned reclen = EXOFS_DIR_REC_LEN(namelen); 310 unsigned long start, n; 311 unsigned long npages = dir_pages(dir); 312 struct page *page = NULL; 313 struct exofs_i_info *oi = exofs_i(dir); 314 struct exofs_dir_entry *de; 315 316 if (npages == 0) 317 goto out; 318 319 *res_page = NULL; 320 321 start = oi->i_dir_start_lookup; 322 if (start >= npages) 323 start = 0; 324 n = start; 325 do { 326 char *kaddr; 327 page = exofs_get_page(dir, n); 328 if (!IS_ERR(page)) { 329 kaddr = page_address(page); 330 de = (struct exofs_dir_entry *) kaddr; 331 kaddr += exofs_last_byte(dir, n) - reclen; 332 while ((char *) de <= kaddr) { 333 if (de->rec_len == 0) { 334 EXOFS_ERR("ERROR: zero-length entry in " 335 "directory(0x%lx)\n", 336 dir->i_ino); 337 exofs_put_page(page); 338 goto out; 339 } 340 if (exofs_match(namelen, name, de)) 341 goto found; 342 de = exofs_next_entry(de); 343 } 344 exofs_put_page(page); 345 } 346 if (++n >= npages) 347 n = 0; 348 } while (n != start); 349out: 350 return NULL; 351 352found: 353 *res_page = page; 354 oi->i_dir_start_lookup = n; 355 return de; 356} 357 358struct exofs_dir_entry *exofs_dotdot(struct inode *dir, struct page **p) 359{ 360 struct page *page = exofs_get_page(dir, 0); 361 struct exofs_dir_entry *de = NULL; 362 363 if (!IS_ERR(page)) { 364 de = exofs_next_entry( 365 (struct exofs_dir_entry *)page_address(page)); 366 *p = page; 367 } 368 return de; 369} 370 371ino_t exofs_parent_ino(struct dentry *child) 372{ 373 struct page *page; 374 struct exofs_dir_entry *de; 375 ino_t ino; 376 377 de = exofs_dotdot(d_inode(child), &page); 378 if (!de) 379 return 0; 380 381 ino = le64_to_cpu(de->inode_no); 382 exofs_put_page(page); 383 return ino; 384} 385 386ino_t exofs_inode_by_name(struct inode *dir, struct dentry *dentry) 387{ 388 ino_t res = 0; 389 struct exofs_dir_entry *de; 390 struct page *page; 391 392 de = exofs_find_entry(dir, dentry, &page); 393 if (de) { 394 res = le64_to_cpu(de->inode_no); 395 exofs_put_page(page); 396 } 397 return res; 398} 399 400int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de, 401 struct page *page, struct inode *inode) 402{ 403 loff_t pos = page_offset(page) + 404 (char *) de - (char *) page_address(page); 405 unsigned len = le16_to_cpu(de->rec_len); 406 int err; 407 408 lock_page(page); 409 err = exofs_write_begin(NULL, page->mapping, pos, len, 0, &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(dir); 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_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(dir); 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(inode); 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 put_page(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_shared = exofs_readdir, 661};