11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/ext2/dir.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1992, 1993, 1994, 1995 51da177e4SLinus Torvalds * Remy Card (card@masi.ibp.fr) 61da177e4SLinus Torvalds * Laboratoire MASI - Institut Blaise Pascal 71da177e4SLinus Torvalds * Universite Pierre et Marie Curie (Paris VI) 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * from 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * linux/fs/minix/dir.c 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * ext2 directory handling functions 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * Big-endian to little-endian byte-swapping/bitmaps by 181da177e4SLinus Torvalds * David S. Miller (davem@caip.rutgers.edu), 1995 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * All code that works with directory layout had been switched to pagecache 211da177e4SLinus Torvalds * and moved here. AV 221da177e4SLinus Torvalds */ 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #include "ext2.h" 25f34fb6ecSNick Piggin #include <linux/buffer_head.h> 261da177e4SLinus Torvalds #include <linux/pagemap.h> 27f34fb6ecSNick Piggin #include <linux/swap.h> 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds typedef struct ext2_dir_entry_2 ext2_dirent; 301da177e4SLinus Torvalds 3140a063f6SEric Sandeen /* 3240a063f6SEric Sandeen * Tests against MAX_REC_LEN etc were put in place for 64k block 3340a063f6SEric Sandeen * sizes; if that is not possible on this arch, we can skip 3440a063f6SEric Sandeen * those tests and speed things up. 3540a063f6SEric Sandeen */ 3689910cccSJan Kara static inline unsigned ext2_rec_len_from_disk(__le16 dlen) 3789910cccSJan Kara { 3889910cccSJan Kara unsigned len = le16_to_cpu(dlen); 3989910cccSJan Kara 40ea1754a0SKirill A. Shutemov #if (PAGE_SIZE >= 65536) 4189910cccSJan Kara if (len == EXT2_MAX_REC_LEN) 4289910cccSJan Kara return 1 << 16; 4340a063f6SEric Sandeen #endif 4489910cccSJan Kara return len; 4589910cccSJan Kara } 4689910cccSJan Kara 4789910cccSJan Kara static inline __le16 ext2_rec_len_to_disk(unsigned len) 4889910cccSJan Kara { 49ea1754a0SKirill A. Shutemov #if (PAGE_SIZE >= 65536) 5089910cccSJan Kara if (len == (1 << 16)) 5189910cccSJan Kara return cpu_to_le16(EXT2_MAX_REC_LEN); 522c11619aSJulia Lawall else 532c11619aSJulia Lawall BUG_ON(len > (1 << 16)); 5440a063f6SEric Sandeen #endif 5589910cccSJan Kara return cpu_to_le16(len); 5689910cccSJan Kara } 5789910cccSJan Kara 581da177e4SLinus Torvalds /* 591da177e4SLinus Torvalds * ext2 uses block-sized chunks. Arguably, sector-sized ones would be 601da177e4SLinus Torvalds * more robust, but we have what we have 611da177e4SLinus Torvalds */ 621da177e4SLinus Torvalds static inline unsigned ext2_chunk_size(struct inode *inode) 631da177e4SLinus Torvalds { 641da177e4SLinus Torvalds return inode->i_sb->s_blocksize; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds static inline void ext2_put_page(struct page *page) 681da177e4SLinus Torvalds { 691da177e4SLinus Torvalds kunmap(page); 7009cbfeafSKirill A. Shutemov put_page(page); 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds /* 741da177e4SLinus Torvalds * Return the offset into page `page_nr' of the last valid 751da177e4SLinus Torvalds * byte in that page, plus one. 761da177e4SLinus Torvalds */ 771da177e4SLinus Torvalds static unsigned 781da177e4SLinus Torvalds ext2_last_byte(struct inode *inode, unsigned long page_nr) 791da177e4SLinus Torvalds { 801da177e4SLinus Torvalds unsigned last_byte = inode->i_size; 811da177e4SLinus Torvalds 8209cbfeafSKirill A. Shutemov last_byte -= page_nr << PAGE_SHIFT; 8309cbfeafSKirill A. Shutemov if (last_byte > PAGE_SIZE) 8409cbfeafSKirill A. Shutemov last_byte = PAGE_SIZE; 851da177e4SLinus Torvalds return last_byte; 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 88f34fb6ecSNick Piggin static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len) 891da177e4SLinus Torvalds { 90f34fb6ecSNick Piggin struct address_space *mapping = page->mapping; 91f34fb6ecSNick Piggin struct inode *dir = mapping->host; 921da177e4SLinus Torvalds int err = 0; 93f34fb6ecSNick Piggin 941da177e4SLinus Torvalds dir->i_version++; 95f34fb6ecSNick Piggin block_write_end(NULL, mapping, pos, len, len, page, NULL); 96f34fb6ecSNick Piggin 97f34fb6ecSNick Piggin if (pos+len > dir->i_size) { 98f34fb6ecSNick Piggin i_size_write(dir, pos+len); 99f34fb6ecSNick Piggin mark_inode_dirty(dir); 100f34fb6ecSNick Piggin } 101f34fb6ecSNick Piggin 1026b7021efSJan Kara if (IS_DIRSYNC(dir)) { 1031da177e4SLinus Torvalds err = write_one_page(page, 1); 1046b7021efSJan Kara if (!err) 105c3765016SChristoph Hellwig err = sync_inode_metadata(dir, 1); 1066b7021efSJan Kara } else { 1071da177e4SLinus Torvalds unlock_page(page); 1086b7021efSJan Kara } 109f34fb6ecSNick Piggin 1101da177e4SLinus Torvalds return err; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 113be5b82dbSAl Viro static bool ext2_check_page(struct page *page, int quiet) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds struct inode *dir = page->mapping->host; 1161da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 1171da177e4SLinus Torvalds unsigned chunk_size = ext2_chunk_size(dir); 1181da177e4SLinus Torvalds char *kaddr = page_address(page); 1191da177e4SLinus Torvalds u32 max_inumber = le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count); 1201da177e4SLinus Torvalds unsigned offs, rec_len; 12109cbfeafSKirill A. Shutemov unsigned limit = PAGE_SIZE; 1221da177e4SLinus Torvalds ext2_dirent *p; 1231da177e4SLinus Torvalds char *error; 1241da177e4SLinus Torvalds 12509cbfeafSKirill A. Shutemov if ((dir->i_size >> PAGE_SHIFT) == page->index) { 12609cbfeafSKirill A. Shutemov limit = dir->i_size & ~PAGE_MASK; 1271da177e4SLinus Torvalds if (limit & (chunk_size - 1)) 1281da177e4SLinus Torvalds goto Ebadsize; 1291da177e4SLinus Torvalds if (!limit) 1301da177e4SLinus Torvalds goto out; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds for (offs = 0; offs <= limit - EXT2_DIR_REC_LEN(1); offs += rec_len) { 1331da177e4SLinus Torvalds p = (ext2_dirent *)(kaddr + offs); 13489910cccSJan Kara rec_len = ext2_rec_len_from_disk(p->rec_len); 1351da177e4SLinus Torvalds 13640a063f6SEric Sandeen if (unlikely(rec_len < EXT2_DIR_REC_LEN(1))) 1371da177e4SLinus Torvalds goto Eshort; 13840a063f6SEric Sandeen if (unlikely(rec_len & 3)) 1391da177e4SLinus Torvalds goto Ealign; 14040a063f6SEric Sandeen if (unlikely(rec_len < EXT2_DIR_REC_LEN(p->name_len))) 1411da177e4SLinus Torvalds goto Enamelen; 14240a063f6SEric Sandeen if (unlikely(((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))) 1431da177e4SLinus Torvalds goto Espan; 14440a063f6SEric Sandeen if (unlikely(le32_to_cpu(p->inode) > max_inumber)) 1451da177e4SLinus Torvalds goto Einumber; 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds if (offs != limit) 1481da177e4SLinus Torvalds goto Eend; 1491da177e4SLinus Torvalds out: 1501da177e4SLinus Torvalds SetPageChecked(page); 151be5b82dbSAl Viro return true; 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds /* Too bad, we had an error */ 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds Ebadsize: 156bd39597cSEric Sandeen if (!quiet) 157bd39597cSEric Sandeen ext2_error(sb, __func__, 158bd39597cSEric Sandeen "size of directory #%lu is not a multiple " 159bd39597cSEric Sandeen "of chunk size", dir->i_ino); 1601da177e4SLinus Torvalds goto fail; 1611da177e4SLinus Torvalds Eshort: 1621da177e4SLinus Torvalds error = "rec_len is smaller than minimal"; 1631da177e4SLinus Torvalds goto bad_entry; 1641da177e4SLinus Torvalds Ealign: 1651da177e4SLinus Torvalds error = "unaligned directory entry"; 1661da177e4SLinus Torvalds goto bad_entry; 1671da177e4SLinus Torvalds Enamelen: 1681da177e4SLinus Torvalds error = "rec_len is too small for name_len"; 1691da177e4SLinus Torvalds goto bad_entry; 1701da177e4SLinus Torvalds Espan: 1711da177e4SLinus Torvalds error = "directory entry across blocks"; 1721da177e4SLinus Torvalds goto bad_entry; 1731da177e4SLinus Torvalds Einumber: 1741da177e4SLinus Torvalds error = "inode out of bounds"; 1751da177e4SLinus Torvalds bad_entry: 176bd39597cSEric Sandeen if (!quiet) 177bd39597cSEric Sandeen ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - " 1781da177e4SLinus Torvalds "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", 17909cbfeafSKirill A. Shutemov dir->i_ino, error, (page->index<<PAGE_SHIFT)+offs, 1801da177e4SLinus Torvalds (unsigned long) le32_to_cpu(p->inode), 1811da177e4SLinus Torvalds rec_len, p->name_len); 1821da177e4SLinus Torvalds goto fail; 1831da177e4SLinus Torvalds Eend: 184bd39597cSEric Sandeen if (!quiet) { 1851da177e4SLinus Torvalds p = (ext2_dirent *)(kaddr + offs); 1861da177e4SLinus Torvalds ext2_error(sb, "ext2_check_page", 1871da177e4SLinus Torvalds "entry in directory #%lu spans the page boundary" 1881da177e4SLinus Torvalds "offset=%lu, inode=%lu", 18909cbfeafSKirill A. Shutemov dir->i_ino, (page->index<<PAGE_SHIFT)+offs, 1901da177e4SLinus Torvalds (unsigned long) le32_to_cpu(p->inode)); 191bd39597cSEric Sandeen } 1921da177e4SLinus Torvalds fail: 1931da177e4SLinus Torvalds SetPageError(page); 194be5b82dbSAl Viro return false; 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds 197bd39597cSEric Sandeen static struct page * ext2_get_page(struct inode *dir, unsigned long n, 198bd39597cSEric Sandeen int quiet) 1991da177e4SLinus Torvalds { 2001da177e4SLinus Torvalds struct address_space *mapping = dir->i_mapping; 201090d2b18SPekka Enberg struct page *page = read_mapping_page(mapping, n, NULL); 2021da177e4SLinus Torvalds if (!IS_ERR(page)) { 2031da177e4SLinus Torvalds kmap(page); 204be5b82dbSAl Viro if (unlikely(!PageChecked(page))) { 205be5b82dbSAl Viro if (PageError(page) || !ext2_check_page(page, quiet)) 2061da177e4SLinus Torvalds goto fail; 2071da177e4SLinus Torvalds } 208be5b82dbSAl Viro } 2091da177e4SLinus Torvalds return page; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds fail: 2121da177e4SLinus Torvalds ext2_put_page(page); 2131da177e4SLinus Torvalds return ERR_PTR(-EIO); 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds /* 2171da177e4SLinus Torvalds * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. 2181da177e4SLinus Torvalds * 2191da177e4SLinus Torvalds * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller. 2201da177e4SLinus Torvalds */ 2211da177e4SLinus Torvalds static inline int ext2_match (int len, const char * const name, 2221da177e4SLinus Torvalds struct ext2_dir_entry_2 * de) 2231da177e4SLinus Torvalds { 2241da177e4SLinus Torvalds if (len != de->name_len) 2251da177e4SLinus Torvalds return 0; 2261da177e4SLinus Torvalds if (!de->inode) 2271da177e4SLinus Torvalds return 0; 2281da177e4SLinus Torvalds return !memcmp(name, de->name, len); 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds /* 2321da177e4SLinus Torvalds * p is at least 6 bytes before the end of page 2331da177e4SLinus Torvalds */ 2341da177e4SLinus Torvalds static inline ext2_dirent *ext2_next_entry(ext2_dirent *p) 2351da177e4SLinus Torvalds { 23689910cccSJan Kara return (ext2_dirent *)((char *)p + 23789910cccSJan Kara ext2_rec_len_from_disk(p->rec_len)); 2381da177e4SLinus Torvalds } 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds static inline unsigned 2411da177e4SLinus Torvalds ext2_validate_entry(char *base, unsigned offset, unsigned mask) 2421da177e4SLinus Torvalds { 2431da177e4SLinus Torvalds ext2_dirent *de = (ext2_dirent*)(base + offset); 2441da177e4SLinus Torvalds ext2_dirent *p = (ext2_dirent*)(base + (offset&mask)); 2451da177e4SLinus Torvalds while ((char*)p < (char*)de) { 2461da177e4SLinus Torvalds if (p->rec_len == 0) 2471da177e4SLinus Torvalds break; 2481da177e4SLinus Torvalds p = ext2_next_entry(p); 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds return (char *)p - base; 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds static unsigned char ext2_filetype_table[EXT2_FT_MAX] = { 2541da177e4SLinus Torvalds [EXT2_FT_UNKNOWN] = DT_UNKNOWN, 2551da177e4SLinus Torvalds [EXT2_FT_REG_FILE] = DT_REG, 2561da177e4SLinus Torvalds [EXT2_FT_DIR] = DT_DIR, 2571da177e4SLinus Torvalds [EXT2_FT_CHRDEV] = DT_CHR, 2581da177e4SLinus Torvalds [EXT2_FT_BLKDEV] = DT_BLK, 2591da177e4SLinus Torvalds [EXT2_FT_FIFO] = DT_FIFO, 2601da177e4SLinus Torvalds [EXT2_FT_SOCK] = DT_SOCK, 2611da177e4SLinus Torvalds [EXT2_FT_SYMLINK] = DT_LNK, 2621da177e4SLinus Torvalds }; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds #define S_SHIFT 12 2651da177e4SLinus Torvalds static unsigned char ext2_type_by_mode[S_IFMT >> S_SHIFT] = { 2661da177e4SLinus Torvalds [S_IFREG >> S_SHIFT] = EXT2_FT_REG_FILE, 2671da177e4SLinus Torvalds [S_IFDIR >> S_SHIFT] = EXT2_FT_DIR, 2681da177e4SLinus Torvalds [S_IFCHR >> S_SHIFT] = EXT2_FT_CHRDEV, 2691da177e4SLinus Torvalds [S_IFBLK >> S_SHIFT] = EXT2_FT_BLKDEV, 2701da177e4SLinus Torvalds [S_IFIFO >> S_SHIFT] = EXT2_FT_FIFO, 2711da177e4SLinus Torvalds [S_IFSOCK >> S_SHIFT] = EXT2_FT_SOCK, 2721da177e4SLinus Torvalds [S_IFLNK >> S_SHIFT] = EXT2_FT_SYMLINK, 2731da177e4SLinus Torvalds }; 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode) 2761da177e4SLinus Torvalds { 2773ea40bc9SAl Viro umode_t mode = inode->i_mode; 2781da177e4SLinus Torvalds if (EXT2_HAS_INCOMPAT_FEATURE(inode->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) 2791da177e4SLinus Torvalds de->file_type = ext2_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; 2801da177e4SLinus Torvalds else 2811da177e4SLinus Torvalds de->file_type = 0; 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds static int 28580886298SAl Viro ext2_readdir(struct file *file, struct dir_context *ctx) 2861da177e4SLinus Torvalds { 28780886298SAl Viro loff_t pos = ctx->pos; 28880886298SAl Viro struct inode *inode = file_inode(file); 2891da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 29009cbfeafSKirill A. Shutemov unsigned int offset = pos & ~PAGE_MASK; 29109cbfeafSKirill A. Shutemov unsigned long n = pos >> PAGE_SHIFT; 2921da177e4SLinus Torvalds unsigned long npages = dir_pages(inode); 2931da177e4SLinus Torvalds unsigned chunk_mask = ~(ext2_chunk_size(inode)-1); 2941da177e4SLinus Torvalds unsigned char *types = NULL; 29580886298SAl Viro int need_revalidate = file->f_version != inode->i_version; 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds if (pos > inode->i_size - EXT2_DIR_REC_LEN(1)) 2982d7f2ea9SAl Viro return 0; 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) 3011da177e4SLinus Torvalds types = ext2_filetype_table; 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds for ( ; n < npages; n++, offset = 0) { 3041da177e4SLinus Torvalds char *kaddr, *limit; 3051da177e4SLinus Torvalds ext2_dirent *de; 306bd39597cSEric Sandeen struct page *page = ext2_get_page(inode, n, 0); 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds if (IS_ERR(page)) { 309605afd60SHarvey Harrison ext2_error(sb, __func__, 3101da177e4SLinus Torvalds "bad page in #%lu", 3111da177e4SLinus Torvalds inode->i_ino); 31209cbfeafSKirill A. Shutemov ctx->pos += PAGE_SIZE - offset; 313bbff2860SAkinobu Mita return PTR_ERR(page); 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds kaddr = page_address(page); 3162d7f2ea9SAl Viro if (unlikely(need_revalidate)) { 3172d7f2ea9SAl Viro if (offset) { 3181da177e4SLinus Torvalds offset = ext2_validate_entry(kaddr, offset, chunk_mask); 31909cbfeafSKirill A. Shutemov ctx->pos = (n<<PAGE_SHIFT) + offset; 3202d7f2ea9SAl Viro } 32180886298SAl Viro file->f_version = inode->i_version; 3221da177e4SLinus Torvalds need_revalidate = 0; 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds de = (ext2_dirent *)(kaddr+offset); 3251da177e4SLinus Torvalds limit = kaddr + ext2_last_byte(inode, n) - EXT2_DIR_REC_LEN(1); 3261da177e4SLinus Torvalds for ( ;(char*)de <= limit; de = ext2_next_entry(de)) { 3271da177e4SLinus Torvalds if (de->rec_len == 0) { 328605afd60SHarvey Harrison ext2_error(sb, __func__, 3291da177e4SLinus Torvalds "zero-length directory entry"); 3301da177e4SLinus Torvalds ext2_put_page(page); 3312d7f2ea9SAl Viro return -EIO; 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds if (de->inode) { 3341da177e4SLinus Torvalds unsigned char d_type = DT_UNKNOWN; 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds if (types && de->file_type < EXT2_FT_MAX) 3371da177e4SLinus Torvalds d_type = types[de->file_type]; 3381da177e4SLinus Torvalds 33980886298SAl Viro if (!dir_emit(ctx, de->name, de->name_len, 34080886298SAl Viro le32_to_cpu(de->inode), 34180886298SAl Viro d_type)) { 3421da177e4SLinus Torvalds ext2_put_page(page); 3432d7f2ea9SAl Viro return 0; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds } 34680886298SAl Viro ctx->pos += ext2_rec_len_from_disk(de->rec_len); 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds ext2_put_page(page); 3491da177e4SLinus Torvalds } 3502d7f2ea9SAl Viro return 0; 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds /* 3541da177e4SLinus Torvalds * ext2_find_entry() 3551da177e4SLinus Torvalds * 3561da177e4SLinus Torvalds * finds an entry in the specified directory with the wanted name. It 35792e12888SJérémy Cochoy * returns the page in which the entry was found (as a parameter - res_page), 35892e12888SJérémy Cochoy * and the entry itself. Page is returned mapped and unlocked. 3591da177e4SLinus Torvalds * Entry is guaranteed to be valid. 3601da177e4SLinus Torvalds */ 3611da177e4SLinus Torvalds struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir, 362ac3ba644SAl Viro const struct qstr *child, struct page **res_page) 3631da177e4SLinus Torvalds { 364a9885444SAl Viro const char *name = child->name; 365a9885444SAl Viro int namelen = child->len; 3661da177e4SLinus Torvalds unsigned reclen = EXT2_DIR_REC_LEN(namelen); 3671da177e4SLinus Torvalds unsigned long start, n; 3681da177e4SLinus Torvalds unsigned long npages = dir_pages(dir); 3691da177e4SLinus Torvalds struct page *page = NULL; 3701da177e4SLinus Torvalds struct ext2_inode_info *ei = EXT2_I(dir); 3711da177e4SLinus Torvalds ext2_dirent * de; 372bd39597cSEric Sandeen int dir_has_error = 0; 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds if (npages == 0) 3751da177e4SLinus Torvalds goto out; 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /* OFFSET_CACHE */ 3781da177e4SLinus Torvalds *res_page = NULL; 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds start = ei->i_dir_start_lookup; 3811da177e4SLinus Torvalds if (start >= npages) 3821da177e4SLinus Torvalds start = 0; 3831da177e4SLinus Torvalds n = start; 3841da177e4SLinus Torvalds do { 3851da177e4SLinus Torvalds char *kaddr; 386bd39597cSEric Sandeen page = ext2_get_page(dir, n, dir_has_error); 3871da177e4SLinus Torvalds if (!IS_ERR(page)) { 3881da177e4SLinus Torvalds kaddr = page_address(page); 3891da177e4SLinus Torvalds de = (ext2_dirent *) kaddr; 3901da177e4SLinus Torvalds kaddr += ext2_last_byte(dir, n) - reclen; 3911da177e4SLinus Torvalds while ((char *) de <= kaddr) { 3921da177e4SLinus Torvalds if (de->rec_len == 0) { 393605afd60SHarvey Harrison ext2_error(dir->i_sb, __func__, 3941da177e4SLinus Torvalds "zero-length directory entry"); 3951da177e4SLinus Torvalds ext2_put_page(page); 3961da177e4SLinus Torvalds goto out; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds if (ext2_match (namelen, name, de)) 3991da177e4SLinus Torvalds goto found; 4001da177e4SLinus Torvalds de = ext2_next_entry(de); 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds ext2_put_page(page); 403bd39597cSEric Sandeen } else 404bd39597cSEric Sandeen dir_has_error = 1; 405bd39597cSEric Sandeen 4061da177e4SLinus Torvalds if (++n >= npages) 4071da177e4SLinus Torvalds n = 0; 408d8adb9ceSEric Sandeen /* next page is past the blocks we've got */ 40909cbfeafSKirill A. Shutemov if (unlikely(n > (dir->i_blocks >> (PAGE_SHIFT - 9)))) { 410605afd60SHarvey Harrison ext2_error(dir->i_sb, __func__, 411d8adb9ceSEric Sandeen "dir %lu size %lld exceeds block count %llu", 412d8adb9ceSEric Sandeen dir->i_ino, dir->i_size, 413d8adb9ceSEric Sandeen (unsigned long long)dir->i_blocks); 414d8adb9ceSEric Sandeen goto out; 415d8adb9ceSEric Sandeen } 4161da177e4SLinus Torvalds } while (n != start); 4171da177e4SLinus Torvalds out: 4181da177e4SLinus Torvalds return NULL; 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds found: 4211da177e4SLinus Torvalds *res_page = page; 4221da177e4SLinus Torvalds ei->i_dir_start_lookup = n; 4231da177e4SLinus Torvalds return de; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p) 4271da177e4SLinus Torvalds { 428bd39597cSEric Sandeen struct page *page = ext2_get_page(dir, 0, 0); 4291da177e4SLinus Torvalds ext2_dirent *de = NULL; 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds if (!IS_ERR(page)) { 4321da177e4SLinus Torvalds de = ext2_next_entry((ext2_dirent *) page_address(page)); 4331da177e4SLinus Torvalds *p = page; 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds return de; 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 438ac3ba644SAl Viro ino_t ext2_inode_by_name(struct inode *dir, const struct qstr *child) 4391da177e4SLinus Torvalds { 4401da177e4SLinus Torvalds ino_t res = 0; 4411da177e4SLinus Torvalds struct ext2_dir_entry_2 *de; 4421da177e4SLinus Torvalds struct page *page; 4431da177e4SLinus Torvalds 444a9885444SAl Viro de = ext2_find_entry (dir, child, &page); 4451da177e4SLinus Torvalds if (de) { 4461da177e4SLinus Torvalds res = le32_to_cpu(de->inode); 4477d93a1a5SEvgeniy Dushistov ext2_put_page(page); 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds return res; 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds 452f4e420dcSChristoph Hellwig static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len) 453f4e420dcSChristoph Hellwig { 4546e1db88dSChristoph Hellwig return __block_write_begin(page, pos, len, ext2_get_block); 455f4e420dcSChristoph Hellwig } 456f4e420dcSChristoph Hellwig 4571da177e4SLinus Torvalds /* Releases the page */ 4581da177e4SLinus Torvalds void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, 45939fe7557SJan Kara struct page *page, struct inode *inode, int update_times) 4601da177e4SLinus Torvalds { 461f34fb6ecSNick Piggin loff_t pos = page_offset(page) + 462f34fb6ecSNick Piggin (char *) de - (char *) page_address(page); 46389910cccSJan Kara unsigned len = ext2_rec_len_from_disk(de->rec_len); 4641da177e4SLinus Torvalds int err; 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds lock_page(page); 467f4e420dcSChristoph Hellwig err = ext2_prepare_chunk(page, pos, len); 468309be53dSEric Sesterhenn BUG_ON(err); 4691da177e4SLinus Torvalds de->inode = cpu_to_le32(inode->i_ino); 4701da177e4SLinus Torvalds ext2_set_de_type(de, inode); 471f34fb6ecSNick Piggin err = ext2_commit_chunk(page, pos, len); 4721da177e4SLinus Torvalds ext2_put_page(page); 47339fe7557SJan Kara if (update_times) 4741da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 4751da177e4SLinus Torvalds EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; 4761da177e4SLinus Torvalds mark_inode_dirty(dir); 4771da177e4SLinus Torvalds } 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds /* 4801da177e4SLinus Torvalds * Parent is locked. 4811da177e4SLinus Torvalds */ 4821da177e4SLinus Torvalds int ext2_add_link (struct dentry *dentry, struct inode *inode) 4831da177e4SLinus Torvalds { 4842b0143b5SDavid Howells struct inode *dir = d_inode(dentry->d_parent); 4851da177e4SLinus Torvalds const char *name = dentry->d_name.name; 4861da177e4SLinus Torvalds int namelen = dentry->d_name.len; 4871da177e4SLinus Torvalds unsigned chunk_size = ext2_chunk_size(dir); 4881da177e4SLinus Torvalds unsigned reclen = EXT2_DIR_REC_LEN(namelen); 4891da177e4SLinus Torvalds unsigned short rec_len, name_len; 4901da177e4SLinus Torvalds struct page *page = NULL; 4911da177e4SLinus Torvalds ext2_dirent * de; 4921da177e4SLinus Torvalds unsigned long npages = dir_pages(dir); 4931da177e4SLinus Torvalds unsigned long n; 4941da177e4SLinus Torvalds char *kaddr; 495f34fb6ecSNick Piggin loff_t pos; 4961da177e4SLinus Torvalds int err; 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds /* 4991da177e4SLinus Torvalds * We take care of directory expansion in the same loop. 5001da177e4SLinus Torvalds * This code plays outside i_size, so it locks the page 5011da177e4SLinus Torvalds * to protect that region. 5021da177e4SLinus Torvalds */ 5031da177e4SLinus Torvalds for (n = 0; n <= npages; n++) { 5041da177e4SLinus Torvalds char *dir_end; 5051da177e4SLinus Torvalds 506bd39597cSEric Sandeen page = ext2_get_page(dir, n, 0); 5071da177e4SLinus Torvalds err = PTR_ERR(page); 5081da177e4SLinus Torvalds if (IS_ERR(page)) 5091da177e4SLinus Torvalds goto out; 5101da177e4SLinus Torvalds lock_page(page); 5111da177e4SLinus Torvalds kaddr = page_address(page); 5121da177e4SLinus Torvalds dir_end = kaddr + ext2_last_byte(dir, n); 5131da177e4SLinus Torvalds de = (ext2_dirent *)kaddr; 51409cbfeafSKirill A. Shutemov kaddr += PAGE_SIZE - reclen; 5151da177e4SLinus Torvalds while ((char *)de <= kaddr) { 5161da177e4SLinus Torvalds if ((char *)de == dir_end) { 5171da177e4SLinus Torvalds /* We hit i_size */ 5181da177e4SLinus Torvalds name_len = 0; 5191da177e4SLinus Torvalds rec_len = chunk_size; 52089910cccSJan Kara de->rec_len = ext2_rec_len_to_disk(chunk_size); 5211da177e4SLinus Torvalds de->inode = 0; 5221da177e4SLinus Torvalds goto got_it; 5231da177e4SLinus Torvalds } 5241da177e4SLinus Torvalds if (de->rec_len == 0) { 525605afd60SHarvey Harrison ext2_error(dir->i_sb, __func__, 5261da177e4SLinus Torvalds "zero-length directory entry"); 5271da177e4SLinus Torvalds err = -EIO; 5281da177e4SLinus Torvalds goto out_unlock; 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds err = -EEXIST; 5311da177e4SLinus Torvalds if (ext2_match (namelen, name, de)) 5321da177e4SLinus Torvalds goto out_unlock; 5331da177e4SLinus Torvalds name_len = EXT2_DIR_REC_LEN(de->name_len); 53489910cccSJan Kara rec_len = ext2_rec_len_from_disk(de->rec_len); 5351da177e4SLinus Torvalds if (!de->inode && rec_len >= reclen) 5361da177e4SLinus Torvalds goto got_it; 5371da177e4SLinus Torvalds if (rec_len >= name_len + reclen) 5381da177e4SLinus Torvalds goto got_it; 5391da177e4SLinus Torvalds de = (ext2_dirent *) ((char *) de + rec_len); 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds unlock_page(page); 5421da177e4SLinus Torvalds ext2_put_page(page); 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds BUG(); 5451da177e4SLinus Torvalds return -EINVAL; 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds got_it: 548f34fb6ecSNick Piggin pos = page_offset(page) + 549f34fb6ecSNick Piggin (char*)de - (char*)page_address(page); 550f4e420dcSChristoph Hellwig err = ext2_prepare_chunk(page, pos, rec_len); 5511da177e4SLinus Torvalds if (err) 5521da177e4SLinus Torvalds goto out_unlock; 5531da177e4SLinus Torvalds if (de->inode) { 5541da177e4SLinus Torvalds ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len); 55589910cccSJan Kara de1->rec_len = ext2_rec_len_to_disk(rec_len - name_len); 55689910cccSJan Kara de->rec_len = ext2_rec_len_to_disk(name_len); 5571da177e4SLinus Torvalds de = de1; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds de->name_len = namelen; 5601da177e4SLinus Torvalds memcpy(de->name, name, namelen); 5611da177e4SLinus Torvalds de->inode = cpu_to_le32(inode->i_ino); 5621da177e4SLinus Torvalds ext2_set_de_type (de, inode); 563f34fb6ecSNick Piggin err = ext2_commit_chunk(page, pos, rec_len); 5641da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 5651da177e4SLinus Torvalds EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; 5661da177e4SLinus Torvalds mark_inode_dirty(dir); 5671da177e4SLinus Torvalds /* OFFSET_CACHE */ 5681da177e4SLinus Torvalds out_put: 5691da177e4SLinus Torvalds ext2_put_page(page); 5701da177e4SLinus Torvalds out: 5711da177e4SLinus Torvalds return err; 5721da177e4SLinus Torvalds out_unlock: 5731da177e4SLinus Torvalds unlock_page(page); 5741da177e4SLinus Torvalds goto out_put; 5751da177e4SLinus Torvalds } 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds /* 5781da177e4SLinus Torvalds * ext2_delete_entry deletes a directory entry by merging it with the 5791da177e4SLinus Torvalds * previous entry. Page is up-to-date. Releases the page. 5801da177e4SLinus Torvalds */ 5811da177e4SLinus Torvalds int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) 5821da177e4SLinus Torvalds { 583f4e420dcSChristoph Hellwig struct inode *inode = page->mapping->host; 5841da177e4SLinus Torvalds char *kaddr = page_address(page); 5851da177e4SLinus Torvalds unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1); 58689910cccSJan Kara unsigned to = ((char *)dir - kaddr) + 58789910cccSJan Kara ext2_rec_len_from_disk(dir->rec_len); 588f34fb6ecSNick Piggin loff_t pos; 5891da177e4SLinus Torvalds ext2_dirent * pde = NULL; 5901da177e4SLinus Torvalds ext2_dirent * de = (ext2_dirent *) (kaddr + from); 5911da177e4SLinus Torvalds int err; 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds while ((char*)de < (char*)dir) { 5941da177e4SLinus Torvalds if (de->rec_len == 0) { 595605afd60SHarvey Harrison ext2_error(inode->i_sb, __func__, 5961da177e4SLinus Torvalds "zero-length directory entry"); 5971da177e4SLinus Torvalds err = -EIO; 5981da177e4SLinus Torvalds goto out; 5991da177e4SLinus Torvalds } 6001da177e4SLinus Torvalds pde = de; 6011da177e4SLinus Torvalds de = ext2_next_entry(de); 6021da177e4SLinus Torvalds } 6031da177e4SLinus Torvalds if (pde) 6041da177e4SLinus Torvalds from = (char*)pde - (char*)page_address(page); 605f34fb6ecSNick Piggin pos = page_offset(page) + from; 6061da177e4SLinus Torvalds lock_page(page); 607f4e420dcSChristoph Hellwig err = ext2_prepare_chunk(page, pos, to - from); 608309be53dSEric Sesterhenn BUG_ON(err); 6091da177e4SLinus Torvalds if (pde) 61089910cccSJan Kara pde->rec_len = ext2_rec_len_to_disk(to - from); 6111da177e4SLinus Torvalds dir->inode = 0; 612f34fb6ecSNick Piggin err = ext2_commit_chunk(page, pos, to - from); 6131da177e4SLinus Torvalds inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; 6141da177e4SLinus Torvalds EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL; 6151da177e4SLinus Torvalds mark_inode_dirty(inode); 6161da177e4SLinus Torvalds out: 6171da177e4SLinus Torvalds ext2_put_page(page); 6181da177e4SLinus Torvalds return err; 6191da177e4SLinus Torvalds } 6201da177e4SLinus Torvalds 6211da177e4SLinus Torvalds /* 6221da177e4SLinus Torvalds * Set the first fragment of directory. 6231da177e4SLinus Torvalds */ 6241da177e4SLinus Torvalds int ext2_make_empty(struct inode *inode, struct inode *parent) 6251da177e4SLinus Torvalds { 626f4e420dcSChristoph Hellwig struct page *page = grab_cache_page(inode->i_mapping, 0); 6271da177e4SLinus Torvalds unsigned chunk_size = ext2_chunk_size(inode); 6281da177e4SLinus Torvalds struct ext2_dir_entry_2 * de; 6291da177e4SLinus Torvalds int err; 6301da177e4SLinus Torvalds void *kaddr; 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds if (!page) 6331da177e4SLinus Torvalds return -ENOMEM; 634f34fb6ecSNick Piggin 635f4e420dcSChristoph Hellwig err = ext2_prepare_chunk(page, 0, chunk_size); 6361da177e4SLinus Torvalds if (err) { 6371da177e4SLinus Torvalds unlock_page(page); 6381da177e4SLinus Torvalds goto fail; 6391da177e4SLinus Torvalds } 640d4a23aeeSCong Wang kaddr = kmap_atomic(page); 6411da177e4SLinus Torvalds memset(kaddr, 0, chunk_size); 6421da177e4SLinus Torvalds de = (struct ext2_dir_entry_2 *)kaddr; 6431da177e4SLinus Torvalds de->name_len = 1; 64489910cccSJan Kara de->rec_len = ext2_rec_len_to_disk(EXT2_DIR_REC_LEN(1)); 6451da177e4SLinus Torvalds memcpy (de->name, ".\0\0", 4); 6461da177e4SLinus Torvalds de->inode = cpu_to_le32(inode->i_ino); 6471da177e4SLinus Torvalds ext2_set_de_type (de, inode); 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds de = (struct ext2_dir_entry_2 *)(kaddr + EXT2_DIR_REC_LEN(1)); 6501da177e4SLinus Torvalds de->name_len = 2; 65189910cccSJan Kara de->rec_len = ext2_rec_len_to_disk(chunk_size - EXT2_DIR_REC_LEN(1)); 6521da177e4SLinus Torvalds de->inode = cpu_to_le32(parent->i_ino); 6531da177e4SLinus Torvalds memcpy (de->name, "..\0", 4); 6541da177e4SLinus Torvalds ext2_set_de_type (de, inode); 655d4a23aeeSCong Wang kunmap_atomic(kaddr); 6561da177e4SLinus Torvalds err = ext2_commit_chunk(page, 0, chunk_size); 6571da177e4SLinus Torvalds fail: 65809cbfeafSKirill A. Shutemov put_page(page); 6591da177e4SLinus Torvalds return err; 6601da177e4SLinus Torvalds } 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds /* 6631da177e4SLinus Torvalds * routine to check that the specified directory is empty (for rmdir) 6641da177e4SLinus Torvalds */ 6651da177e4SLinus Torvalds int ext2_empty_dir (struct inode * inode) 6661da177e4SLinus Torvalds { 6671da177e4SLinus Torvalds struct page *page = NULL; 6681da177e4SLinus Torvalds unsigned long i, npages = dir_pages(inode); 669bd39597cSEric Sandeen int dir_has_error = 0; 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds for (i = 0; i < npages; i++) { 6721da177e4SLinus Torvalds char *kaddr; 6731da177e4SLinus Torvalds ext2_dirent * de; 674bd39597cSEric Sandeen page = ext2_get_page(inode, i, dir_has_error); 6751da177e4SLinus Torvalds 676bd39597cSEric Sandeen if (IS_ERR(page)) { 677bd39597cSEric Sandeen dir_has_error = 1; 6781da177e4SLinus Torvalds continue; 679bd39597cSEric Sandeen } 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds kaddr = page_address(page); 6821da177e4SLinus Torvalds de = (ext2_dirent *)kaddr; 6831da177e4SLinus Torvalds kaddr += ext2_last_byte(inode, i) - EXT2_DIR_REC_LEN(1); 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds while ((char *)de <= kaddr) { 6861da177e4SLinus Torvalds if (de->rec_len == 0) { 687605afd60SHarvey Harrison ext2_error(inode->i_sb, __func__, 6881da177e4SLinus Torvalds "zero-length directory entry"); 6891da177e4SLinus Torvalds printk("kaddr=%p, de=%p\n", kaddr, de); 6901da177e4SLinus Torvalds goto not_empty; 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds if (de->inode != 0) { 6931da177e4SLinus Torvalds /* check for . and .. */ 6941da177e4SLinus Torvalds if (de->name[0] != '.') 6951da177e4SLinus Torvalds goto not_empty; 6961da177e4SLinus Torvalds if (de->name_len > 2) 6971da177e4SLinus Torvalds goto not_empty; 6981da177e4SLinus Torvalds if (de->name_len < 2) { 6991da177e4SLinus Torvalds if (de->inode != 7001da177e4SLinus Torvalds cpu_to_le32(inode->i_ino)) 7011da177e4SLinus Torvalds goto not_empty; 7021da177e4SLinus Torvalds } else if (de->name[1] != '.') 7031da177e4SLinus Torvalds goto not_empty; 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds de = ext2_next_entry(de); 7061da177e4SLinus Torvalds } 7071da177e4SLinus Torvalds ext2_put_page(page); 7081da177e4SLinus Torvalds } 7091da177e4SLinus Torvalds return 1; 7101da177e4SLinus Torvalds 7111da177e4SLinus Torvalds not_empty: 7121da177e4SLinus Torvalds ext2_put_page(page); 7131da177e4SLinus Torvalds return 0; 7141da177e4SLinus Torvalds } 7151da177e4SLinus Torvalds 7164b6f5d20SArjan van de Ven const struct file_operations ext2_dir_operations = { 7171da177e4SLinus Torvalds .llseek = generic_file_llseek, 7181da177e4SLinus Torvalds .read = generic_read_dir, 7193b0a3c1aSAl Viro .iterate_shared = ext2_readdir, 72014f9f7b2SAndi Kleen .unlocked_ioctl = ext2_ioctl, 721e322ff07SDavid Howells #ifdef CONFIG_COMPAT 722e322ff07SDavid Howells .compat_ioctl = ext2_compat_ioctl, 723e322ff07SDavid Howells #endif 72448bde86dSJan Kara .fsync = ext2_fsync, 7251da177e4SLinus Torvalds }; 726