1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/fs/ext2/dir.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1992, 1993, 1994, 1995 61da177e4SLinus Torvalds * Remy Card (card@masi.ibp.fr) 71da177e4SLinus Torvalds * Laboratoire MASI - Institut Blaise Pascal 81da177e4SLinus Torvalds * Universite Pierre et Marie Curie (Paris VI) 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * from 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * linux/fs/minix/dir.c 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * ext2 directory handling functions 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * Big-endian to little-endian byte-swapping/bitmaps by 191da177e4SLinus Torvalds * David S. Miller (davem@caip.rutgers.edu), 1995 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * All code that works with directory layout had been switched to pagecache 221da177e4SLinus Torvalds * and moved here. AV 231da177e4SLinus Torvalds */ 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include "ext2.h" 26f34fb6ecSNick Piggin #include <linux/buffer_head.h> 271da177e4SLinus Torvalds #include <linux/pagemap.h> 28f34fb6ecSNick Piggin #include <linux/swap.h> 29e1d747d9SJeff Layton #include <linux/iversion.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds typedef struct ext2_dir_entry_2 ext2_dirent; 321da177e4SLinus Torvalds 3340a063f6SEric Sandeen /* 3440a063f6SEric Sandeen * Tests against MAX_REC_LEN etc were put in place for 64k block 3540a063f6SEric Sandeen * sizes; if that is not possible on this arch, we can skip 3640a063f6SEric Sandeen * those tests and speed things up. 3740a063f6SEric Sandeen */ 3889910cccSJan Kara static inline unsigned ext2_rec_len_from_disk(__le16 dlen) 3989910cccSJan Kara { 4089910cccSJan Kara unsigned len = le16_to_cpu(dlen); 4189910cccSJan Kara 42ea1754a0SKirill A. Shutemov #if (PAGE_SIZE >= 65536) 4389910cccSJan Kara if (len == EXT2_MAX_REC_LEN) 4489910cccSJan Kara return 1 << 16; 4540a063f6SEric Sandeen #endif 4689910cccSJan Kara return len; 4789910cccSJan Kara } 4889910cccSJan Kara 4989910cccSJan Kara static inline __le16 ext2_rec_len_to_disk(unsigned len) 5089910cccSJan Kara { 51ea1754a0SKirill A. Shutemov #if (PAGE_SIZE >= 65536) 5289910cccSJan Kara if (len == (1 << 16)) 5389910cccSJan Kara return cpu_to_le16(EXT2_MAX_REC_LEN); 542c11619aSJulia Lawall else 552c11619aSJulia Lawall BUG_ON(len > (1 << 16)); 5640a063f6SEric Sandeen #endif 5789910cccSJan Kara return cpu_to_le16(len); 5889910cccSJan Kara } 5989910cccSJan Kara 601da177e4SLinus Torvalds /* 611da177e4SLinus Torvalds * ext2 uses block-sized chunks. Arguably, sector-sized ones would be 621da177e4SLinus Torvalds * more robust, but we have what we have 631da177e4SLinus Torvalds */ 641da177e4SLinus Torvalds static inline unsigned ext2_chunk_size(struct inode *inode) 651da177e4SLinus Torvalds { 661da177e4SLinus Torvalds return inode->i_sb->s_blocksize; 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds /* 701da177e4SLinus Torvalds * Return the offset into page `page_nr' of the last valid 711da177e4SLinus Torvalds * byte in that page, plus one. 721da177e4SLinus Torvalds */ 731da177e4SLinus Torvalds static unsigned 741da177e4SLinus Torvalds ext2_last_byte(struct inode *inode, unsigned long page_nr) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds unsigned last_byte = inode->i_size; 771da177e4SLinus Torvalds 7809cbfeafSKirill A. Shutemov last_byte -= page_nr << PAGE_SHIFT; 7909cbfeafSKirill A. Shutemov if (last_byte > PAGE_SIZE) 8009cbfeafSKirill A. Shutemov last_byte = PAGE_SIZE; 811da177e4SLinus Torvalds return last_byte; 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds 84f34fb6ecSNick Piggin static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len) 851da177e4SLinus Torvalds { 86f34fb6ecSNick Piggin struct address_space *mapping = page->mapping; 87f34fb6ecSNick Piggin struct inode *dir = mapping->host; 881da177e4SLinus Torvalds int err = 0; 89f34fb6ecSNick Piggin 90e1d747d9SJeff Layton inode_inc_iversion(dir); 91f34fb6ecSNick Piggin block_write_end(NULL, mapping, pos, len, len, page, NULL); 92f34fb6ecSNick Piggin 93f34fb6ecSNick Piggin if (pos+len > dir->i_size) { 94f34fb6ecSNick Piggin i_size_write(dir, pos+len); 95f34fb6ecSNick Piggin mark_inode_dirty(dir); 96f34fb6ecSNick Piggin } 97f34fb6ecSNick Piggin 986b7021efSJan Kara if (IS_DIRSYNC(dir)) { 992b69c828SJeff Layton err = write_one_page(page); 1006b7021efSJan Kara if (!err) 101c3765016SChristoph Hellwig err = sync_inode_metadata(dir, 1); 1026b7021efSJan Kara } else { 1031da177e4SLinus Torvalds unlock_page(page); 1046b7021efSJan Kara } 105f34fb6ecSNick Piggin 1061da177e4SLinus Torvalds return err; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 109be5b82dbSAl Viro static bool ext2_check_page(struct page *page, int quiet) 1101da177e4SLinus Torvalds { 1111da177e4SLinus Torvalds struct inode *dir = page->mapping->host; 1121da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 1131da177e4SLinus Torvalds unsigned chunk_size = ext2_chunk_size(dir); 1141da177e4SLinus Torvalds char *kaddr = page_address(page); 1151da177e4SLinus Torvalds u32 max_inumber = le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count); 1161da177e4SLinus Torvalds unsigned offs, rec_len; 11709cbfeafSKirill A. Shutemov unsigned limit = PAGE_SIZE; 1181da177e4SLinus Torvalds ext2_dirent *p; 1191da177e4SLinus Torvalds char *error; 1201da177e4SLinus Torvalds 12109cbfeafSKirill A. Shutemov if ((dir->i_size >> PAGE_SHIFT) == page->index) { 12209cbfeafSKirill A. Shutemov limit = dir->i_size & ~PAGE_MASK; 1231da177e4SLinus Torvalds if (limit & (chunk_size - 1)) 1241da177e4SLinus Torvalds goto Ebadsize; 1251da177e4SLinus Torvalds if (!limit) 1261da177e4SLinus Torvalds goto out; 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds for (offs = 0; offs <= limit - EXT2_DIR_REC_LEN(1); offs += rec_len) { 1291da177e4SLinus Torvalds p = (ext2_dirent *)(kaddr + offs); 13089910cccSJan Kara rec_len = ext2_rec_len_from_disk(p->rec_len); 1311da177e4SLinus Torvalds 13240a063f6SEric Sandeen if (unlikely(rec_len < EXT2_DIR_REC_LEN(1))) 1331da177e4SLinus Torvalds goto Eshort; 13440a063f6SEric Sandeen if (unlikely(rec_len & 3)) 1351da177e4SLinus Torvalds goto Ealign; 13640a063f6SEric Sandeen if (unlikely(rec_len < EXT2_DIR_REC_LEN(p->name_len))) 1371da177e4SLinus Torvalds goto Enamelen; 13840a063f6SEric Sandeen if (unlikely(((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))) 1391da177e4SLinus Torvalds goto Espan; 14040a063f6SEric Sandeen if (unlikely(le32_to_cpu(p->inode) > max_inumber)) 1411da177e4SLinus Torvalds goto Einumber; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds if (offs != limit) 1441da177e4SLinus Torvalds goto Eend; 1451da177e4SLinus Torvalds out: 1461da177e4SLinus Torvalds SetPageChecked(page); 147be5b82dbSAl Viro return true; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds /* Too bad, we had an error */ 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds Ebadsize: 152bd39597cSEric Sandeen if (!quiet) 153bd39597cSEric Sandeen ext2_error(sb, __func__, 154bd39597cSEric Sandeen "size of directory #%lu is not a multiple " 155bd39597cSEric Sandeen "of chunk size", dir->i_ino); 1561da177e4SLinus Torvalds goto fail; 1571da177e4SLinus Torvalds Eshort: 1581da177e4SLinus Torvalds error = "rec_len is smaller than minimal"; 1591da177e4SLinus Torvalds goto bad_entry; 1601da177e4SLinus Torvalds Ealign: 1611da177e4SLinus Torvalds error = "unaligned directory entry"; 1621da177e4SLinus Torvalds goto bad_entry; 1631da177e4SLinus Torvalds Enamelen: 1641da177e4SLinus Torvalds error = "rec_len is too small for name_len"; 1651da177e4SLinus Torvalds goto bad_entry; 1661da177e4SLinus Torvalds Espan: 1671da177e4SLinus Torvalds error = "directory entry across blocks"; 1681da177e4SLinus Torvalds goto bad_entry; 1691da177e4SLinus Torvalds Einumber: 1701da177e4SLinus Torvalds error = "inode out of bounds"; 1711da177e4SLinus Torvalds bad_entry: 172bd39597cSEric Sandeen if (!quiet) 173bd39597cSEric Sandeen ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - " 1741da177e4SLinus Torvalds "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", 17509cbfeafSKirill A. Shutemov dir->i_ino, error, (page->index<<PAGE_SHIFT)+offs, 1761da177e4SLinus Torvalds (unsigned long) le32_to_cpu(p->inode), 1771da177e4SLinus Torvalds rec_len, p->name_len); 1781da177e4SLinus Torvalds goto fail; 1791da177e4SLinus Torvalds Eend: 180bd39597cSEric Sandeen if (!quiet) { 1811da177e4SLinus Torvalds p = (ext2_dirent *)(kaddr + offs); 1821da177e4SLinus Torvalds ext2_error(sb, "ext2_check_page", 1831da177e4SLinus Torvalds "entry in directory #%lu spans the page boundary" 1841da177e4SLinus Torvalds "offset=%lu, inode=%lu", 18509cbfeafSKirill A. Shutemov dir->i_ino, (page->index<<PAGE_SHIFT)+offs, 1861da177e4SLinus Torvalds (unsigned long) le32_to_cpu(p->inode)); 187bd39597cSEric Sandeen } 1881da177e4SLinus Torvalds fail: 1891da177e4SLinus Torvalds SetPageError(page); 190be5b82dbSAl Viro return false; 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 193bd39597cSEric Sandeen static struct page * ext2_get_page(struct inode *dir, unsigned long n, 194bd39597cSEric Sandeen int quiet) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds struct address_space *mapping = dir->i_mapping; 197090d2b18SPekka Enberg struct page *page = read_mapping_page(mapping, n, NULL); 1981da177e4SLinus Torvalds if (!IS_ERR(page)) { 1991da177e4SLinus Torvalds kmap(page); 200be5b82dbSAl Viro if (unlikely(!PageChecked(page))) { 201be5b82dbSAl Viro if (PageError(page) || !ext2_check_page(page, quiet)) 2021da177e4SLinus Torvalds goto fail; 2031da177e4SLinus Torvalds } 204be5b82dbSAl Viro } 2051da177e4SLinus Torvalds return page; 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds fail: 2081da177e4SLinus Torvalds ext2_put_page(page); 2091da177e4SLinus Torvalds return ERR_PTR(-EIO); 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* 2131da177e4SLinus Torvalds * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. 2141da177e4SLinus Torvalds * 2151da177e4SLinus Torvalds * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller. 2161da177e4SLinus Torvalds */ 2171da177e4SLinus Torvalds static inline int ext2_match (int len, const char * const name, 2181da177e4SLinus Torvalds struct ext2_dir_entry_2 * de) 2191da177e4SLinus Torvalds { 2201da177e4SLinus Torvalds if (len != de->name_len) 2211da177e4SLinus Torvalds return 0; 2221da177e4SLinus Torvalds if (!de->inode) 2231da177e4SLinus Torvalds return 0; 2241da177e4SLinus Torvalds return !memcmp(name, de->name, len); 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds /* 2281da177e4SLinus Torvalds * p is at least 6 bytes before the end of page 2291da177e4SLinus Torvalds */ 2301da177e4SLinus Torvalds static inline ext2_dirent *ext2_next_entry(ext2_dirent *p) 2311da177e4SLinus Torvalds { 23289910cccSJan Kara return (ext2_dirent *)((char *)p + 23389910cccSJan Kara ext2_rec_len_from_disk(p->rec_len)); 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds static inline unsigned 2371da177e4SLinus Torvalds ext2_validate_entry(char *base, unsigned offset, unsigned mask) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds ext2_dirent *de = (ext2_dirent*)(base + offset); 2401da177e4SLinus Torvalds ext2_dirent *p = (ext2_dirent*)(base + (offset&mask)); 2411da177e4SLinus Torvalds while ((char*)p < (char*)de) { 2421da177e4SLinus Torvalds if (p->rec_len == 0) 2431da177e4SLinus Torvalds break; 2441da177e4SLinus Torvalds p = ext2_next_entry(p); 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds return (char *)p - base; 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode) 2501da177e4SLinus Torvalds { 2511da177e4SLinus Torvalds if (EXT2_HAS_INCOMPAT_FEATURE(inode->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) 252e1089218SPhillip Potter de->file_type = fs_umode_to_ftype(inode->i_mode); 2531da177e4SLinus Torvalds else 2541da177e4SLinus Torvalds de->file_type = 0; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds static int 25880886298SAl Viro ext2_readdir(struct file *file, struct dir_context *ctx) 2591da177e4SLinus Torvalds { 26080886298SAl Viro loff_t pos = ctx->pos; 26180886298SAl Viro struct inode *inode = file_inode(file); 2621da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 26309cbfeafSKirill A. Shutemov unsigned int offset = pos & ~PAGE_MASK; 26409cbfeafSKirill A. Shutemov unsigned long n = pos >> PAGE_SHIFT; 2651da177e4SLinus Torvalds unsigned long npages = dir_pages(inode); 2661da177e4SLinus Torvalds unsigned chunk_mask = ~(ext2_chunk_size(inode)-1); 267c472c07bSGoffredo Baroncelli bool need_revalidate = !inode_eq_iversion(inode, file->f_version); 268e1089218SPhillip Potter bool has_filetype; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds if (pos > inode->i_size - EXT2_DIR_REC_LEN(1)) 2712d7f2ea9SAl Viro return 0; 2721da177e4SLinus Torvalds 273e1089218SPhillip Potter has_filetype = 274e1089218SPhillip Potter EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds for ( ; n < npages; n++, offset = 0) { 2771da177e4SLinus Torvalds char *kaddr, *limit; 2781da177e4SLinus Torvalds ext2_dirent *de; 279bd39597cSEric Sandeen struct page *page = ext2_get_page(inode, n, 0); 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds if (IS_ERR(page)) { 282605afd60SHarvey Harrison ext2_error(sb, __func__, 2831da177e4SLinus Torvalds "bad page in #%lu", 2841da177e4SLinus Torvalds inode->i_ino); 28509cbfeafSKirill A. Shutemov ctx->pos += PAGE_SIZE - offset; 286bbff2860SAkinobu Mita return PTR_ERR(page); 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds kaddr = page_address(page); 2892d7f2ea9SAl Viro if (unlikely(need_revalidate)) { 2902d7f2ea9SAl Viro if (offset) { 2911da177e4SLinus Torvalds offset = ext2_validate_entry(kaddr, offset, chunk_mask); 29209cbfeafSKirill A. Shutemov ctx->pos = (n<<PAGE_SHIFT) + offset; 2932d7f2ea9SAl Viro } 294e1d747d9SJeff Layton file->f_version = inode_query_iversion(inode); 295e1d747d9SJeff Layton need_revalidate = false; 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds de = (ext2_dirent *)(kaddr+offset); 2981da177e4SLinus Torvalds limit = kaddr + ext2_last_byte(inode, n) - EXT2_DIR_REC_LEN(1); 2991da177e4SLinus Torvalds for ( ;(char*)de <= limit; de = ext2_next_entry(de)) { 3001da177e4SLinus Torvalds if (de->rec_len == 0) { 301605afd60SHarvey Harrison ext2_error(sb, __func__, 3021da177e4SLinus Torvalds "zero-length directory entry"); 3031da177e4SLinus Torvalds ext2_put_page(page); 3042d7f2ea9SAl Viro return -EIO; 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds if (de->inode) { 3071da177e4SLinus Torvalds unsigned char d_type = DT_UNKNOWN; 3081da177e4SLinus Torvalds 309e1089218SPhillip Potter if (has_filetype) 310e1089218SPhillip Potter d_type = fs_ftype_to_dtype(de->file_type); 3111da177e4SLinus Torvalds 31280886298SAl Viro if (!dir_emit(ctx, de->name, de->name_len, 31380886298SAl Viro le32_to_cpu(de->inode), 31480886298SAl Viro d_type)) { 3151da177e4SLinus Torvalds ext2_put_page(page); 3162d7f2ea9SAl Viro return 0; 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds } 31980886298SAl Viro ctx->pos += ext2_rec_len_from_disk(de->rec_len); 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds ext2_put_page(page); 3221da177e4SLinus Torvalds } 3232d7f2ea9SAl Viro return 0; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds /* 3271da177e4SLinus Torvalds * ext2_find_entry() 3281da177e4SLinus Torvalds * 3291da177e4SLinus Torvalds * finds an entry in the specified directory with the wanted name. It 33092e12888SJérémy Cochoy * returns the page in which the entry was found (as a parameter - res_page), 33192e12888SJérémy Cochoy * and the entry itself. Page is returned mapped and unlocked. 3321da177e4SLinus Torvalds * Entry is guaranteed to be valid. 333*a6fbd0abSIra Weiny * 334*a6fbd0abSIra Weiny * On Success ext2_put_page() should be called on *res_page. 3351da177e4SLinus Torvalds */ 3361da177e4SLinus Torvalds struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir, 337ac3ba644SAl Viro const struct qstr *child, struct page **res_page) 3381da177e4SLinus Torvalds { 339a9885444SAl Viro const char *name = child->name; 340a9885444SAl Viro int namelen = child->len; 3411da177e4SLinus Torvalds unsigned reclen = EXT2_DIR_REC_LEN(namelen); 3421da177e4SLinus Torvalds unsigned long start, n; 3431da177e4SLinus Torvalds unsigned long npages = dir_pages(dir); 3441da177e4SLinus Torvalds struct page *page = NULL; 3451da177e4SLinus Torvalds struct ext2_inode_info *ei = EXT2_I(dir); 3461da177e4SLinus Torvalds ext2_dirent * de; 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds if (npages == 0) 3491da177e4SLinus Torvalds goto out; 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds /* OFFSET_CACHE */ 3521da177e4SLinus Torvalds *res_page = NULL; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds start = ei->i_dir_start_lookup; 3551da177e4SLinus Torvalds if (start >= npages) 3561da177e4SLinus Torvalds start = 0; 3571da177e4SLinus Torvalds n = start; 3581da177e4SLinus Torvalds do { 3591da177e4SLinus Torvalds char *kaddr; 360b4962091Szhangyi (F) page = ext2_get_page(dir, n, 0); 361b4962091Szhangyi (F) if (IS_ERR(page)) 362b4962091Szhangyi (F) return ERR_CAST(page); 363b4962091Szhangyi (F) 3641da177e4SLinus Torvalds kaddr = page_address(page); 3651da177e4SLinus Torvalds de = (ext2_dirent *) kaddr; 3661da177e4SLinus Torvalds kaddr += ext2_last_byte(dir, n) - reclen; 3671da177e4SLinus Torvalds while ((char *) de <= kaddr) { 3681da177e4SLinus Torvalds if (de->rec_len == 0) { 369605afd60SHarvey Harrison ext2_error(dir->i_sb, __func__, 3701da177e4SLinus Torvalds "zero-length directory entry"); 3711da177e4SLinus Torvalds ext2_put_page(page); 3721da177e4SLinus Torvalds goto out; 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds if (ext2_match(namelen, name, de)) 3751da177e4SLinus Torvalds goto found; 3761da177e4SLinus Torvalds de = ext2_next_entry(de); 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds ext2_put_page(page); 379bd39597cSEric Sandeen 3801da177e4SLinus Torvalds if (++n >= npages) 3811da177e4SLinus Torvalds n = 0; 382d8adb9ceSEric Sandeen /* next page is past the blocks we've got */ 38309cbfeafSKirill A. Shutemov if (unlikely(n > (dir->i_blocks >> (PAGE_SHIFT - 9)))) { 384605afd60SHarvey Harrison ext2_error(dir->i_sb, __func__, 385d8adb9ceSEric Sandeen "dir %lu size %lld exceeds block count %llu", 386d8adb9ceSEric Sandeen dir->i_ino, dir->i_size, 387d8adb9ceSEric Sandeen (unsigned long long)dir->i_blocks); 388d8adb9ceSEric Sandeen goto out; 389d8adb9ceSEric Sandeen } 3901da177e4SLinus Torvalds } while (n != start); 3911da177e4SLinus Torvalds out: 392a43850a3Szhangyi (F) return ERR_PTR(-ENOENT); 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds found: 3951da177e4SLinus Torvalds *res_page = page; 3961da177e4SLinus Torvalds ei->i_dir_start_lookup = n; 3971da177e4SLinus Torvalds return de; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 400*a6fbd0abSIra Weiny /** 401*a6fbd0abSIra Weiny * Return the '..' directory entry and the page in which the entry was found 402*a6fbd0abSIra Weiny * (as a parameter - p). 403*a6fbd0abSIra Weiny * 404*a6fbd0abSIra Weiny * On Success ext2_put_page() should be called on *p. 405*a6fbd0abSIra Weiny */ 4061da177e4SLinus Torvalds struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p) 4071da177e4SLinus Torvalds { 408bd39597cSEric Sandeen struct page *page = ext2_get_page(dir, 0, 0); 4091da177e4SLinus Torvalds ext2_dirent *de = NULL; 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds if (!IS_ERR(page)) { 4121da177e4SLinus Torvalds de = ext2_next_entry((ext2_dirent *) page_address(page)); 4131da177e4SLinus Torvalds *p = page; 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds return de; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 418b4962091Szhangyi (F) int ext2_inode_by_name(struct inode *dir, const struct qstr *child, ino_t *ino) 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds struct ext2_dir_entry_2 *de; 4211da177e4SLinus Torvalds struct page *page; 4221da177e4SLinus Torvalds 423a9885444SAl Viro de = ext2_find_entry(dir, child, &page); 424a43850a3Szhangyi (F) if (IS_ERR(de)) 425b4962091Szhangyi (F) return PTR_ERR(de); 426b4962091Szhangyi (F) 427b4962091Szhangyi (F) *ino = le32_to_cpu(de->inode); 4287d93a1a5SEvgeniy Dushistov ext2_put_page(page); 429b4962091Szhangyi (F) return 0; 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds 432f4e420dcSChristoph Hellwig static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len) 433f4e420dcSChristoph Hellwig { 4346e1db88dSChristoph Hellwig return __block_write_begin(page, pos, len, ext2_get_block); 435f4e420dcSChristoph Hellwig } 436f4e420dcSChristoph Hellwig 4371da177e4SLinus Torvalds /* Releases the page */ 4381da177e4SLinus Torvalds void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, 43939fe7557SJan Kara struct page *page, struct inode *inode, int update_times) 4401da177e4SLinus Torvalds { 441f34fb6ecSNick Piggin loff_t pos = page_offset(page) + 442f34fb6ecSNick Piggin (char *) de - (char *) page_address(page); 44389910cccSJan Kara unsigned len = ext2_rec_len_from_disk(de->rec_len); 4441da177e4SLinus Torvalds int err; 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds lock_page(page); 447f4e420dcSChristoph Hellwig err = ext2_prepare_chunk(page, pos, len); 448309be53dSEric Sesterhenn BUG_ON(err); 4491da177e4SLinus Torvalds de->inode = cpu_to_le32(inode->i_ino); 4501da177e4SLinus Torvalds ext2_set_de_type(de, inode); 451f34fb6ecSNick Piggin err = ext2_commit_chunk(page, pos, len); 4521da177e4SLinus Torvalds ext2_put_page(page); 45339fe7557SJan Kara if (update_times) 45402027d42SDeepa Dinamani dir->i_mtime = dir->i_ctime = current_time(dir); 4551da177e4SLinus Torvalds EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; 4561da177e4SLinus Torvalds mark_inode_dirty(dir); 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds /* 4601da177e4SLinus Torvalds * Parent is locked. 4611da177e4SLinus Torvalds */ 4621da177e4SLinus Torvalds int ext2_add_link (struct dentry *dentry, struct inode *inode) 4631da177e4SLinus Torvalds { 4642b0143b5SDavid Howells struct inode *dir = d_inode(dentry->d_parent); 4651da177e4SLinus Torvalds const char *name = dentry->d_name.name; 4661da177e4SLinus Torvalds int namelen = dentry->d_name.len; 4671da177e4SLinus Torvalds unsigned chunk_size = ext2_chunk_size(dir); 4681da177e4SLinus Torvalds unsigned reclen = EXT2_DIR_REC_LEN(namelen); 4691da177e4SLinus Torvalds unsigned short rec_len, name_len; 4701da177e4SLinus Torvalds struct page *page = NULL; 4711da177e4SLinus Torvalds ext2_dirent * de; 4721da177e4SLinus Torvalds unsigned long npages = dir_pages(dir); 4731da177e4SLinus Torvalds unsigned long n; 4741da177e4SLinus Torvalds char *kaddr; 475f34fb6ecSNick Piggin loff_t pos; 4761da177e4SLinus Torvalds int err; 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds /* 4791da177e4SLinus Torvalds * We take care of directory expansion in the same loop. 4801da177e4SLinus Torvalds * This code plays outside i_size, so it locks the page 4811da177e4SLinus Torvalds * to protect that region. 4821da177e4SLinus Torvalds */ 4831da177e4SLinus Torvalds for (n = 0; n <= npages; n++) { 4841da177e4SLinus Torvalds char *dir_end; 4851da177e4SLinus Torvalds 486bd39597cSEric Sandeen page = ext2_get_page(dir, n, 0); 4871da177e4SLinus Torvalds err = PTR_ERR(page); 4881da177e4SLinus Torvalds if (IS_ERR(page)) 4891da177e4SLinus Torvalds goto out; 4901da177e4SLinus Torvalds lock_page(page); 4911da177e4SLinus Torvalds kaddr = page_address(page); 4921da177e4SLinus Torvalds dir_end = kaddr + ext2_last_byte(dir, n); 4931da177e4SLinus Torvalds de = (ext2_dirent *)kaddr; 49409cbfeafSKirill A. Shutemov kaddr += PAGE_SIZE - reclen; 4951da177e4SLinus Torvalds while ((char *)de <= kaddr) { 4961da177e4SLinus Torvalds if ((char *)de == dir_end) { 4971da177e4SLinus Torvalds /* We hit i_size */ 4981da177e4SLinus Torvalds name_len = 0; 4991da177e4SLinus Torvalds rec_len = chunk_size; 50089910cccSJan Kara de->rec_len = ext2_rec_len_to_disk(chunk_size); 5011da177e4SLinus Torvalds de->inode = 0; 5021da177e4SLinus Torvalds goto got_it; 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds if (de->rec_len == 0) { 505605afd60SHarvey Harrison ext2_error(dir->i_sb, __func__, 5061da177e4SLinus Torvalds "zero-length directory entry"); 5071da177e4SLinus Torvalds err = -EIO; 5081da177e4SLinus Torvalds goto out_unlock; 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds err = -EEXIST; 5111da177e4SLinus Torvalds if (ext2_match (namelen, name, de)) 5121da177e4SLinus Torvalds goto out_unlock; 5131da177e4SLinus Torvalds name_len = EXT2_DIR_REC_LEN(de->name_len); 51489910cccSJan Kara rec_len = ext2_rec_len_from_disk(de->rec_len); 5151da177e4SLinus Torvalds if (!de->inode && rec_len >= reclen) 5161da177e4SLinus Torvalds goto got_it; 5171da177e4SLinus Torvalds if (rec_len >= name_len + reclen) 5181da177e4SLinus Torvalds goto got_it; 5191da177e4SLinus Torvalds de = (ext2_dirent *) ((char *) de + rec_len); 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds unlock_page(page); 5221da177e4SLinus Torvalds ext2_put_page(page); 5231da177e4SLinus Torvalds } 5241da177e4SLinus Torvalds BUG(); 5251da177e4SLinus Torvalds return -EINVAL; 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds got_it: 528f34fb6ecSNick Piggin pos = page_offset(page) + 529f34fb6ecSNick Piggin (char*)de - (char*)page_address(page); 530f4e420dcSChristoph Hellwig err = ext2_prepare_chunk(page, pos, rec_len); 5311da177e4SLinus Torvalds if (err) 5321da177e4SLinus Torvalds goto out_unlock; 5331da177e4SLinus Torvalds if (de->inode) { 5341da177e4SLinus Torvalds ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len); 53589910cccSJan Kara de1->rec_len = ext2_rec_len_to_disk(rec_len - name_len); 53689910cccSJan Kara de->rec_len = ext2_rec_len_to_disk(name_len); 5371da177e4SLinus Torvalds de = de1; 5381da177e4SLinus Torvalds } 5391da177e4SLinus Torvalds de->name_len = namelen; 5401da177e4SLinus Torvalds memcpy(de->name, name, namelen); 5411da177e4SLinus Torvalds de->inode = cpu_to_le32(inode->i_ino); 5421da177e4SLinus Torvalds ext2_set_de_type (de, inode); 543f34fb6ecSNick Piggin err = ext2_commit_chunk(page, pos, rec_len); 54402027d42SDeepa Dinamani dir->i_mtime = dir->i_ctime = current_time(dir); 5451da177e4SLinus Torvalds EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; 5461da177e4SLinus Torvalds mark_inode_dirty(dir); 5471da177e4SLinus Torvalds /* OFFSET_CACHE */ 5481da177e4SLinus Torvalds out_put: 5491da177e4SLinus Torvalds ext2_put_page(page); 5501da177e4SLinus Torvalds out: 5511da177e4SLinus Torvalds return err; 5521da177e4SLinus Torvalds out_unlock: 5531da177e4SLinus Torvalds unlock_page(page); 5541da177e4SLinus Torvalds goto out_put; 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds /* 5581da177e4SLinus Torvalds * ext2_delete_entry deletes a directory entry by merging it with the 5591da177e4SLinus Torvalds * previous entry. Page is up-to-date. Releases the page. 5601da177e4SLinus Torvalds */ 5611da177e4SLinus Torvalds int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) 5621da177e4SLinus Torvalds { 563f4e420dcSChristoph Hellwig struct inode *inode = page->mapping->host; 5641da177e4SLinus Torvalds char *kaddr = page_address(page); 5651da177e4SLinus Torvalds unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1); 56689910cccSJan Kara unsigned to = ((char *)dir - kaddr) + 56789910cccSJan Kara ext2_rec_len_from_disk(dir->rec_len); 568f34fb6ecSNick Piggin loff_t pos; 5691da177e4SLinus Torvalds ext2_dirent * pde = NULL; 5701da177e4SLinus Torvalds ext2_dirent * de = (ext2_dirent *) (kaddr + from); 5711da177e4SLinus Torvalds int err; 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds while ((char*)de < (char*)dir) { 5741da177e4SLinus Torvalds if (de->rec_len == 0) { 575605afd60SHarvey Harrison ext2_error(inode->i_sb, __func__, 5761da177e4SLinus Torvalds "zero-length directory entry"); 5771da177e4SLinus Torvalds err = -EIO; 5781da177e4SLinus Torvalds goto out; 5791da177e4SLinus Torvalds } 5801da177e4SLinus Torvalds pde = de; 5811da177e4SLinus Torvalds de = ext2_next_entry(de); 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds if (pde) 5841da177e4SLinus Torvalds from = (char*)pde - (char*)page_address(page); 585f34fb6ecSNick Piggin pos = page_offset(page) + from; 5861da177e4SLinus Torvalds lock_page(page); 587f4e420dcSChristoph Hellwig err = ext2_prepare_chunk(page, pos, to - from); 588309be53dSEric Sesterhenn BUG_ON(err); 5891da177e4SLinus Torvalds if (pde) 59089910cccSJan Kara pde->rec_len = ext2_rec_len_to_disk(to - from); 5911da177e4SLinus Torvalds dir->inode = 0; 592f34fb6ecSNick Piggin err = ext2_commit_chunk(page, pos, to - from); 59302027d42SDeepa Dinamani inode->i_ctime = inode->i_mtime = current_time(inode); 5941da177e4SLinus Torvalds EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL; 5951da177e4SLinus Torvalds mark_inode_dirty(inode); 5961da177e4SLinus Torvalds out: 5971da177e4SLinus Torvalds ext2_put_page(page); 5981da177e4SLinus Torvalds return err; 5991da177e4SLinus Torvalds } 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds /* 6021da177e4SLinus Torvalds * Set the first fragment of directory. 6031da177e4SLinus Torvalds */ 6041da177e4SLinus Torvalds int ext2_make_empty(struct inode *inode, struct inode *parent) 6051da177e4SLinus Torvalds { 606f4e420dcSChristoph Hellwig struct page *page = grab_cache_page(inode->i_mapping, 0); 6071da177e4SLinus Torvalds unsigned chunk_size = ext2_chunk_size(inode); 6081da177e4SLinus Torvalds struct ext2_dir_entry_2 * de; 6091da177e4SLinus Torvalds int err; 6101da177e4SLinus Torvalds void *kaddr; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds if (!page) 6131da177e4SLinus Torvalds return -ENOMEM; 614f34fb6ecSNick Piggin 615f4e420dcSChristoph Hellwig err = ext2_prepare_chunk(page, 0, chunk_size); 6161da177e4SLinus Torvalds if (err) { 6171da177e4SLinus Torvalds unlock_page(page); 6181da177e4SLinus Torvalds goto fail; 6191da177e4SLinus Torvalds } 620d4a23aeeSCong Wang kaddr = kmap_atomic(page); 6211da177e4SLinus Torvalds memset(kaddr, 0, chunk_size); 6221da177e4SLinus Torvalds de = (struct ext2_dir_entry_2 *)kaddr; 6231da177e4SLinus Torvalds de->name_len = 1; 62489910cccSJan Kara de->rec_len = ext2_rec_len_to_disk(EXT2_DIR_REC_LEN(1)); 6251da177e4SLinus Torvalds memcpy (de->name, ".\0\0", 4); 6261da177e4SLinus Torvalds de->inode = cpu_to_le32(inode->i_ino); 6271da177e4SLinus Torvalds ext2_set_de_type (de, inode); 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds de = (struct ext2_dir_entry_2 *)(kaddr + EXT2_DIR_REC_LEN(1)); 6301da177e4SLinus Torvalds de->name_len = 2; 63189910cccSJan Kara de->rec_len = ext2_rec_len_to_disk(chunk_size - EXT2_DIR_REC_LEN(1)); 6321da177e4SLinus Torvalds de->inode = cpu_to_le32(parent->i_ino); 6331da177e4SLinus Torvalds memcpy (de->name, "..\0", 4); 6341da177e4SLinus Torvalds ext2_set_de_type (de, inode); 635d4a23aeeSCong Wang kunmap_atomic(kaddr); 6361da177e4SLinus Torvalds err = ext2_commit_chunk(page, 0, chunk_size); 6371da177e4SLinus Torvalds fail: 63809cbfeafSKirill A. Shutemov put_page(page); 6391da177e4SLinus Torvalds return err; 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds /* 6431da177e4SLinus Torvalds * routine to check that the specified directory is empty (for rmdir) 6441da177e4SLinus Torvalds */ 6451da177e4SLinus Torvalds int ext2_empty_dir (struct inode * inode) 6461da177e4SLinus Torvalds { 6471da177e4SLinus Torvalds struct page *page = NULL; 6481da177e4SLinus Torvalds unsigned long i, npages = dir_pages(inode); 649bd39597cSEric Sandeen int dir_has_error = 0; 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds for (i = 0; i < npages; i++) { 6521da177e4SLinus Torvalds char *kaddr; 6531da177e4SLinus Torvalds ext2_dirent * de; 654bd39597cSEric Sandeen page = ext2_get_page(inode, i, dir_has_error); 6551da177e4SLinus Torvalds 656bd39597cSEric Sandeen if (IS_ERR(page)) { 657bd39597cSEric Sandeen dir_has_error = 1; 6581da177e4SLinus Torvalds continue; 659bd39597cSEric Sandeen } 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds kaddr = page_address(page); 6621da177e4SLinus Torvalds de = (ext2_dirent *)kaddr; 6631da177e4SLinus Torvalds kaddr += ext2_last_byte(inode, i) - EXT2_DIR_REC_LEN(1); 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds while ((char *)de <= kaddr) { 6661da177e4SLinus Torvalds if (de->rec_len == 0) { 667605afd60SHarvey Harrison ext2_error(inode->i_sb, __func__, 6681da177e4SLinus Torvalds "zero-length directory entry"); 6691da177e4SLinus Torvalds printk("kaddr=%p, de=%p\n", kaddr, de); 6701da177e4SLinus Torvalds goto not_empty; 6711da177e4SLinus Torvalds } 6721da177e4SLinus Torvalds if (de->inode != 0) { 6731da177e4SLinus Torvalds /* check for . and .. */ 6741da177e4SLinus Torvalds if (de->name[0] != '.') 6751da177e4SLinus Torvalds goto not_empty; 6761da177e4SLinus Torvalds if (de->name_len > 2) 6771da177e4SLinus Torvalds goto not_empty; 6781da177e4SLinus Torvalds if (de->name_len < 2) { 6791da177e4SLinus Torvalds if (de->inode != 6801da177e4SLinus Torvalds cpu_to_le32(inode->i_ino)) 6811da177e4SLinus Torvalds goto not_empty; 6821da177e4SLinus Torvalds } else if (de->name[1] != '.') 6831da177e4SLinus Torvalds goto not_empty; 6841da177e4SLinus Torvalds } 6851da177e4SLinus Torvalds de = ext2_next_entry(de); 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds ext2_put_page(page); 6881da177e4SLinus Torvalds } 6891da177e4SLinus Torvalds return 1; 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds not_empty: 6921da177e4SLinus Torvalds ext2_put_page(page); 6931da177e4SLinus Torvalds return 0; 6941da177e4SLinus Torvalds } 6951da177e4SLinus Torvalds 6964b6f5d20SArjan van de Ven const struct file_operations ext2_dir_operations = { 6971da177e4SLinus Torvalds .llseek = generic_file_llseek, 6981da177e4SLinus Torvalds .read = generic_read_dir, 6993b0a3c1aSAl Viro .iterate_shared = ext2_readdir, 70014f9f7b2SAndi Kleen .unlocked_ioctl = ext2_ioctl, 701e322ff07SDavid Howells #ifdef CONFIG_COMPAT 702e322ff07SDavid Howells .compat_ioctl = ext2_compat_ioctl, 703e322ff07SDavid Howells #endif 70448bde86dSJan Kara .fsync = ext2_fsync, 7051da177e4SLinus Torvalds }; 706