b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * linux/fs/ext2/dir.c
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * Copyright (C) 1992, 1993, 1994, 1995
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) * Remy Card (card@masi.ibp.fr)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) * Laboratoire MASI - Institut Blaise Pascal
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) * Universite Pierre et Marie Curie (Paris VI)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) * from
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12) * linux/fs/minix/dir.c
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14) * Copyright (C) 1991, 1992 Linus Torvalds
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 16) * ext2 directory handling functions
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18) * Big-endian to little-endian byte-swapping/bitmaps by
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19) * David S. Miller (davem@caip.rutgers.edu), 1995
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) * All code that works with directory layout had been switched to pagecache
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 22) * and moved here. AV
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 24)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 25) #include "ext2.h"
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 26) #include <linux/buffer_head.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 27) #include <linux/pagemap.h>
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 28) #include <linux/swap.h>
e1d747d9b6728 (Jeff Layton 2017-12-11 06:35:14 -0500 29) #include <linux/iversion.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) typedef struct ext2_dir_entry_2 ext2_dirent;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 32)
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 33) /*
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 34) * Tests against MAX_REC_LEN etc were put in place for 64k block
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 35) * sizes; if that is not possible on this arch, we can skip
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 36) * those tests and speed things up.
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 37) */
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 38) static inline unsigned ext2_rec_len_from_disk(__le16 dlen)
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 39) {
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 40) unsigned len = le16_to_cpu(dlen);
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 41)
ea1754a084760 (Kirill A. Shutemov 2016-04-01 15:29:48 +0300 42) #if (PAGE_SIZE >= 65536)
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 43) if (len == EXT2_MAX_REC_LEN)
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 44) return 1 << 16;
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 45) #endif
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 46) return len;
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 47) }
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 48)
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 49) static inline __le16 ext2_rec_len_to_disk(unsigned len)
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 50) {
ea1754a084760 (Kirill A. Shutemov 2016-04-01 15:29:48 +0300 51) #if (PAGE_SIZE >= 65536)
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 52) if (len == (1 << 16))
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 53) return cpu_to_le16(EXT2_MAX_REC_LEN);
2c11619a590e1 (Julia Lawall 2008-04-28 02:16:02 -0700 54) else
2c11619a590e1 (Julia Lawall 2008-04-28 02:16:02 -0700 55) BUG_ON(len > (1 << 16));
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 56) #endif
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 57) return cpu_to_le16(len);
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 58) }
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 59)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 61) * ext2 uses block-sized chunks. Arguably, sector-sized ones would be
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 62) * more robust, but we have what we have
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 63) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 64) static inline unsigned ext2_chunk_size(struct inode *inode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 65) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 66) return inode->i_sb->s_blocksize;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 67) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 68)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 69) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 70) * Return the offset into page `page_nr' of the last valid
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) * byte in that page, plus one.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) static unsigned
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) ext2_last_byte(struct inode *inode, unsigned long page_nr)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 76) unsigned last_byte = inode->i_size;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 77)
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 78) last_byte -= page_nr << PAGE_SHIFT;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 79) if (last_byte > PAGE_SIZE)
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 80) last_byte = PAGE_SIZE;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 81) return last_byte;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 82) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 83)
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 84) static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 85) {
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 86) struct address_space *mapping = page->mapping;
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 87) struct inode *dir = mapping->host;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 88) int err = 0;
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 89)
e1d747d9b6728 (Jeff Layton 2017-12-11 06:35:14 -0500 90) inode_inc_iversion(dir);
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 91) block_write_end(NULL, mapping, pos, len, len, page, NULL);
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 92)
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 93) if (pos+len > dir->i_size) {
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 94) i_size_write(dir, pos+len);
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 95) mark_inode_dirty(dir);
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 96) }
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 97)
6b7021ef7e1a7 (Jan Kara 2009-01-15 13:51:29 -0800 98) if (IS_DIRSYNC(dir)) {
2b69c8280c8b2 (Jeff Layton 2017-07-05 15:26:48 -0400 99) err = write_one_page(page);
6b7021ef7e1a7 (Jan Kara 2009-01-15 13:51:29 -0800 100) if (!err)
c37650161a53c (Christoph Hellwig 2010-10-06 10:48:20 +0200 101) err = sync_inode_metadata(dir, 1);
6b7021ef7e1a7 (Jan Kara 2009-01-15 13:51:29 -0800 102) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 103) unlock_page(page);
6b7021ef7e1a7 (Jan Kara 2009-01-15 13:51:29 -0800 104) }
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 105)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 106) return err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 107) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 108)
89e34995bdd78 (Javier Pello 2021-07-14 18:54:48 +0200 109) static bool ext2_check_page(struct page *page, int quiet, char *kaddr)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 110) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 111) struct inode *dir = page->mapping->host;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 112) struct super_block *sb = dir->i_sb;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 113) unsigned chunk_size = ext2_chunk_size(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 114) u32 max_inumber = le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 115) unsigned offs, rec_len;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 116) unsigned limit = PAGE_SIZE;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 117) ext2_dirent *p;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 118) char *error;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 119)
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 120) if ((dir->i_size >> PAGE_SHIFT) == page->index) {
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 121) limit = dir->i_size & ~PAGE_MASK;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 122) if (limit & (chunk_size - 1))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 123) goto Ebadsize;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 124) if (!limit)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 125) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 126) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 127) for (offs = 0; offs <= limit - EXT2_DIR_REC_LEN(1); offs += rec_len) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 128) p = (ext2_dirent *)(kaddr + offs);
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 129) rec_len = ext2_rec_len_from_disk(p->rec_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 130)
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 131) if (unlikely(rec_len < EXT2_DIR_REC_LEN(1)))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 132) goto Eshort;
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 133) if (unlikely(rec_len & 3))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 134) goto Ealign;
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 135) if (unlikely(rec_len < EXT2_DIR_REC_LEN(p->name_len)))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 136) goto Enamelen;
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 137) if (unlikely(((offs + rec_len - 1) ^ offs) & ~(chunk_size-1)))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 138) goto Espan;
40a063f6691ce (Eric Sandeen 2010-12-07 11:51:05 -0600 139) if (unlikely(le32_to_cpu(p->inode) > max_inumber))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 140) goto Einumber;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 141) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 142) if (offs != limit)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 143) goto Eend;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 144) out:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 145) SetPageChecked(page);
be5b82dbfec2a (Al Viro 2016-04-22 15:06:44 -0400 146) return true;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 147)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 148) /* Too bad, we had an error */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 149)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 150) Ebadsize:
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 151) if (!quiet)
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 152) ext2_error(sb, __func__,
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 153) "size of directory #%lu is not a multiple "
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 154) "of chunk size", dir->i_ino);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 155) goto fail;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 156) Eshort:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 157) error = "rec_len is smaller than minimal";
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 158) goto bad_entry;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 159) Ealign:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 160) error = "unaligned directory entry";
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 161) goto bad_entry;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 162) Enamelen:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 163) error = "rec_len is too small for name_len";
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 164) goto bad_entry;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 165) Espan:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 166) error = "directory entry across blocks";
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 167) goto bad_entry;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 168) Einumber:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 169) error = "inode out of bounds";
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 170) bad_entry:
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 171) if (!quiet)
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 172) ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - "
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 173) "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 174) dir->i_ino, error, (page->index<<PAGE_SHIFT)+offs,
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 175) (unsigned long) le32_to_cpu(p->inode),
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 176) rec_len, p->name_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 177) goto fail;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 178) Eend:
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 179) if (!quiet) {
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 180) p = (ext2_dirent *)(kaddr + offs);
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 181) ext2_error(sb, "ext2_check_page",
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 182) "entry in directory #%lu spans the page boundary"
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 183) "offset=%lu, inode=%lu",
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 184) dir->i_ino, (page->index<<PAGE_SHIFT)+offs,
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 185) (unsigned long) le32_to_cpu(p->inode));
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 186) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 187) fail:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 188) SetPageError(page);
be5b82dbfec2a (Al Viro 2016-04-22 15:06:44 -0400 189) return false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 190) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 191)
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 192) /*
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 193) * Calls to ext2_get_page()/ext2_put_page() must be nested according to the
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 194) * rules documented in kmap_local_page()/kunmap_local().
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 195) *
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 196) * NOTE: ext2_find_entry() and ext2_dotdot() act as a call to ext2_get_page()
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 197) * and should be treated as a call to ext2_get_page() for nesting purposes.
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 198) */
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 199) static struct page * ext2_get_page(struct inode *dir, unsigned long n,
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 200) int quiet, void **page_addr)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 201) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 202) struct address_space *mapping = dir->i_mapping;
090d2b185d868 (Pekka Enberg 2006-06-23 02:05:08 -0700 203) struct page *page = read_mapping_page(mapping, n, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 204) if (!IS_ERR(page)) {
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 205) *page_addr = kmap_local_page(page);
be5b82dbfec2a (Al Viro 2016-04-22 15:06:44 -0400 206) if (unlikely(!PageChecked(page))) {
89e34995bdd78 (Javier Pello 2021-07-14 18:54:48 +0200 207) if (PageError(page) || !ext2_check_page(page, quiet,
89e34995bdd78 (Javier Pello 2021-07-14 18:54:48 +0200 208) *page_addr))
be5b82dbfec2a (Al Viro 2016-04-22 15:06:44 -0400 209) goto fail;
be5b82dbfec2a (Al Viro 2016-04-22 15:06:44 -0400 210) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 211) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 212) return page;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 213)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 214) fail:
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 215) ext2_put_page(page, *page_addr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 216) return ERR_PTR(-EIO);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 217) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 218)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 219) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 220) * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 221) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 222) * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 223) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 224) static inline int ext2_match (int len, const char * const name,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 225) struct ext2_dir_entry_2 * de)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 226) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 227) if (len != de->name_len)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 228) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 229) if (!de->inode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 230) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 231) return !memcmp(name, de->name, len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 232) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 233)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 234) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 235) * p is at least 6 bytes before the end of page
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 236) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 237) static inline ext2_dirent *ext2_next_entry(ext2_dirent *p)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 238) {
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 239) return (ext2_dirent *)((char *)p +
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 240) ext2_rec_len_from_disk(p->rec_len));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 241) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 242)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 243) static inline unsigned
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 244) ext2_validate_entry(char *base, unsigned offset, unsigned mask)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 245) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 246) ext2_dirent *de = (ext2_dirent*)(base + offset);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 247) ext2_dirent *p = (ext2_dirent*)(base + (offset&mask));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 248) while ((char*)p < (char*)de) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 249) if (p->rec_len == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 250) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 251) p = ext2_next_entry(p);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 252) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 253) return (char *)p - base;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 254) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 255)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 256) static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 257) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 258) if (EXT2_HAS_INCOMPAT_FEATURE(inode->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
e108921894289 (Phillip Potter 2019-01-21 00:54:31 +0000 259) de->file_type = fs_umode_to_ftype(inode->i_mode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 260) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 261) de->file_type = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 262) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 263)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 264) static int
80886298c0723 (Al Viro 2013-05-15 18:51:49 -0400 265) ext2_readdir(struct file *file, struct dir_context *ctx)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 266) {
80886298c0723 (Al Viro 2013-05-15 18:51:49 -0400 267) loff_t pos = ctx->pos;
80886298c0723 (Al Viro 2013-05-15 18:51:49 -0400 268) struct inode *inode = file_inode(file);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 269) struct super_block *sb = inode->i_sb;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 270) unsigned int offset = pos & ~PAGE_MASK;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 271) unsigned long n = pos >> PAGE_SHIFT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 272) unsigned long npages = dir_pages(inode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 273) unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
c472c07bfed9c (Goffredo Baroncelli 2018-02-01 08:15:25 -0500 274) bool need_revalidate = !inode_eq_iversion(inode, file->f_version);
e108921894289 (Phillip Potter 2019-01-21 00:54:31 +0000 275) bool has_filetype;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 276)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 277) if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
2d7f2ea9c9898 (Al Viro 2006-03-15 21:41:59 +0000 278) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 279)
e108921894289 (Phillip Potter 2019-01-21 00:54:31 +0000 280) has_filetype =
e108921894289 (Phillip Potter 2019-01-21 00:54:31 +0000 281) EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 282)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 283) for ( ; n < npages; n++, offset = 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 284) char *kaddr, *limit;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 285) ext2_dirent *de;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 286) struct page *page = ext2_get_page(inode, n, 0, (void **)&kaddr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 287)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 288) if (IS_ERR(page)) {
605afd60ef6dd (Harvey Harrison 2008-04-28 02:16:03 -0700 289) ext2_error(sb, __func__,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 290) "bad page in #%lu",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 291) inode->i_ino);
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 292) ctx->pos += PAGE_SIZE - offset;
bbff28602436c (Akinobu Mita 2008-04-28 02:16:00 -0700 293) return PTR_ERR(page);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 294) }
2d7f2ea9c9898 (Al Viro 2006-03-15 21:41:59 +0000 295) if (unlikely(need_revalidate)) {
2d7f2ea9c9898 (Al Viro 2006-03-15 21:41:59 +0000 296) if (offset) {
2d7f2ea9c9898 (Al Viro 2006-03-15 21:41:59 +0000 297) offset = ext2_validate_entry(kaddr, offset, chunk_mask);
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 298) ctx->pos = (n<<PAGE_SHIFT) + offset;
2d7f2ea9c9898 (Al Viro 2006-03-15 21:41:59 +0000 299) }
e1d747d9b6728 (Jeff Layton 2017-12-11 06:35:14 -0500 300) file->f_version = inode_query_iversion(inode);
e1d747d9b6728 (Jeff Layton 2017-12-11 06:35:14 -0500 301) need_revalidate = false;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 302) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 303) de = (ext2_dirent *)(kaddr+offset);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 304) limit = kaddr + ext2_last_byte(inode, n) - EXT2_DIR_REC_LEN(1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 305) for ( ;(char*)de <= limit; de = ext2_next_entry(de)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 306) if (de->rec_len == 0) {
605afd60ef6dd (Harvey Harrison 2008-04-28 02:16:03 -0700 307) ext2_error(sb, __func__,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 308) "zero-length directory entry");
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 309) ext2_put_page(page, kaddr);
2d7f2ea9c9898 (Al Viro 2006-03-15 21:41:59 +0000 310) return -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 311) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 312) if (de->inode) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 313) unsigned char d_type = DT_UNKNOWN;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 314)
e108921894289 (Phillip Potter 2019-01-21 00:54:31 +0000 315) if (has_filetype)
e108921894289 (Phillip Potter 2019-01-21 00:54:31 +0000 316) d_type = fs_ftype_to_dtype(de->file_type);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 317)
80886298c0723 (Al Viro 2013-05-15 18:51:49 -0400 318) if (!dir_emit(ctx, de->name, de->name_len,
80886298c0723 (Al Viro 2013-05-15 18:51:49 -0400 319) le32_to_cpu(de->inode),
80886298c0723 (Al Viro 2013-05-15 18:51:49 -0400 320) d_type)) {
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 321) ext2_put_page(page, kaddr);
2d7f2ea9c9898 (Al Viro 2006-03-15 21:41:59 +0000 322) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 323) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 324) }
80886298c0723 (Al Viro 2013-05-15 18:51:49 -0400 325) ctx->pos += ext2_rec_len_from_disk(de->rec_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 326) }
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 327) ext2_put_page(page, kaddr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 328) }
2d7f2ea9c9898 (Al Viro 2006-03-15 21:41:59 +0000 329) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 330) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 331)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 332) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 333) * ext2_find_entry()
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 334) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 335) * finds an entry in the specified directory with the wanted name. It
92e128884bf04 (Jérémy Cochoy 2009-11-30 17:58:43 +0100 336) * returns the page in which the entry was found (as a parameter - res_page),
92e128884bf04 (Jérémy Cochoy 2009-11-30 17:58:43 +0100 337) * and the entry itself. Page is returned mapped and unlocked.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 338) * Entry is guaranteed to be valid.
a6fbd0ab3d7a1 (Ira Weiny 2020-11-12 09:42:44 -0800 339) *
a6fbd0ab3d7a1 (Ira Weiny 2020-11-12 09:42:44 -0800 340) * On Success ext2_put_page() should be called on *res_page.
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 341) *
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 342) * NOTE: Calls to ext2_get_page()/ext2_put_page() must be nested according to
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 343) * the rules documented in kmap_local_page()/kunmap_local().
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 344) *
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 345) * ext2_find_entry() and ext2_dotdot() act as a call to ext2_get_page() and
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 346) * should be treated as a call to ext2_get_page() for nesting purposes.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 347) */
ac3ba644bc8f9 (Al Viro 2016-07-20 22:47:26 -0400 348) struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir,
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 349) const struct qstr *child, struct page **res_page,
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 350) void **res_page_addr)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 351) {
a9885444f7ff6 (Al Viro 2008-08-24 07:28:39 -0400 352) const char *name = child->name;
a9885444f7ff6 (Al Viro 2008-08-24 07:28:39 -0400 353) int namelen = child->len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 354) unsigned reclen = EXT2_DIR_REC_LEN(namelen);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 355) unsigned long start, n;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 356) unsigned long npages = dir_pages(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 357) struct page *page = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 358) struct ext2_inode_info *ei = EXT2_I(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 359) ext2_dirent * de;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 360) void *page_addr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 361)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 362) if (npages == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 363) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 364)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 365) /* OFFSET_CACHE */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 366) *res_page = NULL;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 367) *res_page_addr = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 368)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 369) start = ei->i_dir_start_lookup;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 370) if (start >= npages)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 371) start = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 372) n = start;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 373) do {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 374) char *kaddr;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 375) page = ext2_get_page(dir, n, 0, &page_addr);
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 376) if (IS_ERR(page))
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 377) return ERR_CAST(page);
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 378)
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 379) kaddr = page_addr;
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 380) de = (ext2_dirent *) kaddr;
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 381) kaddr += ext2_last_byte(dir, n) - reclen;
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 382) while ((char *) de <= kaddr) {
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 383) if (de->rec_len == 0) {
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 384) ext2_error(dir->i_sb, __func__,
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 385) "zero-length directory entry");
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 386) ext2_put_page(page, page_addr);
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 387) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 388) }
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 389) if (ext2_match(namelen, name, de))
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 390) goto found;
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 391) de = ext2_next_entry(de);
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 392) }
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 393) ext2_put_page(page, page_addr);
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 394)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 395) if (++n >= npages)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 396) n = 0;
d8adb9cef7e40 (Eric Sandeen 2007-02-10 01:45:06 -0800 397) /* next page is past the blocks we've got */
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 398) if (unlikely(n > (dir->i_blocks >> (PAGE_SHIFT - 9)))) {
605afd60ef6dd (Harvey Harrison 2008-04-28 02:16:03 -0700 399) ext2_error(dir->i_sb, __func__,
d8adb9cef7e40 (Eric Sandeen 2007-02-10 01:45:06 -0800 400) "dir %lu size %lld exceeds block count %llu",
d8adb9cef7e40 (Eric Sandeen 2007-02-10 01:45:06 -0800 401) dir->i_ino, dir->i_size,
d8adb9cef7e40 (Eric Sandeen 2007-02-10 01:45:06 -0800 402) (unsigned long long)dir->i_blocks);
d8adb9cef7e40 (Eric Sandeen 2007-02-10 01:45:06 -0800 403) goto out;
d8adb9cef7e40 (Eric Sandeen 2007-02-10 01:45:06 -0800 404) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 405) } while (n != start);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 406) out:
a43850a380ef5 (zhangyi (F) 2020-06-08 11:40:43 +0800 407) return ERR_PTR(-ENOENT);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 408)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 409) found:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 410) *res_page = page;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 411) *res_page_addr = page_addr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 412) ei->i_dir_start_lookup = n;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 413) return de;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 414) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 415)
a6fbd0ab3d7a1 (Ira Weiny 2020-11-12 09:42:44 -0800 416) /**
a6fbd0ab3d7a1 (Ira Weiny 2020-11-12 09:42:44 -0800 417) * Return the '..' directory entry and the page in which the entry was found
a6fbd0ab3d7a1 (Ira Weiny 2020-11-12 09:42:44 -0800 418) * (as a parameter - p).
a6fbd0ab3d7a1 (Ira Weiny 2020-11-12 09:42:44 -0800 419) *
a6fbd0ab3d7a1 (Ira Weiny 2020-11-12 09:42:44 -0800 420) * On Success ext2_put_page() should be called on *p.
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 421) *
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 422) * NOTE: Calls to ext2_get_page()/ext2_put_page() must be nested according to
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 423) * the rules documented in kmap_local_page()/kunmap_local().
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 424) *
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 425) * ext2_find_entry() and ext2_dotdot() act as a call to ext2_get_page() and
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 426) * should be treated as a call to ext2_get_page() for nesting purposes.
a6fbd0ab3d7a1 (Ira Weiny 2020-11-12 09:42:44 -0800 427) */
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 428) struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p,
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 429) void **pa)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 430) {
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 431) void *page_addr;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 432) struct page *page = ext2_get_page(dir, 0, 0, &page_addr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 433) ext2_dirent *de = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 434)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 435) if (!IS_ERR(page)) {
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 436) de = ext2_next_entry((ext2_dirent *) page_addr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 437) *p = page;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 438) *pa = page_addr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 439) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 440) return de;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 441) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 442)
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 443) int ext2_inode_by_name(struct inode *dir, const struct qstr *child, ino_t *ino)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 444) {
a9885444f7ff6 (Al Viro 2008-08-24 07:28:39 -0400 445) struct ext2_dir_entry_2 *de;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 446) struct page *page;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 447) void *page_addr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 448)
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 449) de = ext2_find_entry(dir, child, &page, &page_addr);
a43850a380ef5 (zhangyi (F) 2020-06-08 11:40:43 +0800 450) if (IS_ERR(de))
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 451) return PTR_ERR(de);
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 452)
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 453) *ino = le32_to_cpu(de->inode);
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 454) ext2_put_page(page, page_addr);
b4962091a54c8 (zhangyi (F) 2020-06-08 11:40:42 +0800 455) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 456) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 457)
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 458) static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len)
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 459) {
6e1db88d536ad (Christoph Hellwig 2010-06-04 11:29:57 +0200 460) return __block_write_begin(page, pos, len, ext2_get_block);
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 461) }
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 462)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 463) void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 464) struct page *page, void *page_addr, struct inode *inode,
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 465) int update_times)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 466) {
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 467) loff_t pos = page_offset(page) +
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 468) (char *) de - (char *) page_addr;
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 469) unsigned len = ext2_rec_len_from_disk(de->rec_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 470) int err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 471)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 472) lock_page(page);
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 473) err = ext2_prepare_chunk(page, pos, len);
309be53da60dc (Eric Sesterhenn 2006-03-26 18:27:41 +0200 474) BUG_ON(err);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 475) de->inode = cpu_to_le32(inode->i_ino);
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 476) ext2_set_de_type(de, inode);
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 477) err = ext2_commit_chunk(page, pos, len);
39fe7557b4d6a (Jan Kara 2009-06-17 16:26:20 -0700 478) if (update_times)
02027d42c3f74 (Deepa Dinamani 2016-09-14 07:48:05 -0700 479) dir->i_mtime = dir->i_ctime = current_time(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 480) EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 481) mark_inode_dirty(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 482) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 483)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 484) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 485) * Parent is locked.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 486) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 487) int ext2_add_link (struct dentry *dentry, struct inode *inode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 488) {
2b0143b5c986b (David Howells 2015-03-17 22:25:59 +0000 489) struct inode *dir = d_inode(dentry->d_parent);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 490) const char *name = dentry->d_name.name;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 491) int namelen = dentry->d_name.len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 492) unsigned chunk_size = ext2_chunk_size(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 493) unsigned reclen = EXT2_DIR_REC_LEN(namelen);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 494) unsigned short rec_len, name_len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 495) struct page *page = NULL;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 496) void *page_addr = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 497) ext2_dirent * de;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 498) unsigned long npages = dir_pages(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 499) unsigned long n;
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 500) loff_t pos;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 501) int err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 502)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 503) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 504) * We take care of directory expansion in the same loop.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 505) * This code plays outside i_size, so it locks the page
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 506) * to protect that region.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 507) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 508) for (n = 0; n <= npages; n++) {
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 509) char *kaddr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 510) char *dir_end;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 511)
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 512) page = ext2_get_page(dir, n, 0, &page_addr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 513) err = PTR_ERR(page);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 514) if (IS_ERR(page))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 515) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 516) lock_page(page);
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 517) kaddr = page_addr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 518) dir_end = kaddr + ext2_last_byte(dir, n);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 519) de = (ext2_dirent *)kaddr;
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 520) kaddr += PAGE_SIZE - reclen;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 521) while ((char *)de <= kaddr) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 522) if ((char *)de == dir_end) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 523) /* We hit i_size */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 524) name_len = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 525) rec_len = chunk_size;
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 526) de->rec_len = ext2_rec_len_to_disk(chunk_size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 527) de->inode = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 528) goto got_it;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 529) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 530) if (de->rec_len == 0) {
605afd60ef6dd (Harvey Harrison 2008-04-28 02:16:03 -0700 531) ext2_error(dir->i_sb, __func__,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 532) "zero-length directory entry");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 533) err = -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 534) goto out_unlock;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 535) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 536) err = -EEXIST;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 537) if (ext2_match (namelen, name, de))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 538) goto out_unlock;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 539) name_len = EXT2_DIR_REC_LEN(de->name_len);
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 540) rec_len = ext2_rec_len_from_disk(de->rec_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 541) if (!de->inode && rec_len >= reclen)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 542) goto got_it;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 543) if (rec_len >= name_len + reclen)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 544) goto got_it;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 545) de = (ext2_dirent *) ((char *) de + rec_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 546) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 547) unlock_page(page);
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 548) ext2_put_page(page, page_addr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 549) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 550) BUG();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 551) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 552)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 553) got_it:
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 554) pos = page_offset(page) +
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 555) (char *)de - (char *)page_addr;
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 556) err = ext2_prepare_chunk(page, pos, rec_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 557) if (err)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 558) goto out_unlock;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 559) if (de->inode) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 560) ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len);
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 561) de1->rec_len = ext2_rec_len_to_disk(rec_len - name_len);
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 562) de->rec_len = ext2_rec_len_to_disk(name_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 563) de = de1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 564) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 565) de->name_len = namelen;
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 566) memcpy(de->name, name, namelen);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 567) de->inode = cpu_to_le32(inode->i_ino);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 568) ext2_set_de_type (de, inode);
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 569) err = ext2_commit_chunk(page, pos, rec_len);
02027d42c3f74 (Deepa Dinamani 2016-09-14 07:48:05 -0700 570) dir->i_mtime = dir->i_ctime = current_time(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 571) EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 572) mark_inode_dirty(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 573) /* OFFSET_CACHE */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 574) out_put:
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 575) ext2_put_page(page, page_addr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 576) out:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 577) return err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 578) out_unlock:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 579) unlock_page(page);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 580) goto out_put;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 581) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 582)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 583) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 584) * ext2_delete_entry deletes a directory entry by merging it with the
e2ebb12304559 (Ira Weiny 2021-03-28 23:54:01 -0700 585) * previous entry. Page is up-to-date.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 586) */
89e34995bdd78 (Javier Pello 2021-07-14 18:54:48 +0200 587) int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
89e34995bdd78 (Javier Pello 2021-07-14 18:54:48 +0200 588) char *kaddr)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 589) {
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 590) struct inode *inode = page->mapping->host;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 591) unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 592) unsigned to = ((char *)dir - kaddr) +
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 593) ext2_rec_len_from_disk(dir->rec_len);
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 594) loff_t pos;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 595) ext2_dirent * pde = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 596) ext2_dirent * de = (ext2_dirent *) (kaddr + from);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 597) int err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 598)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 599) while ((char*)de < (char*)dir) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 600) if (de->rec_len == 0) {
605afd60ef6dd (Harvey Harrison 2008-04-28 02:16:03 -0700 601) ext2_error(inode->i_sb, __func__,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 602) "zero-length directory entry");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 603) err = -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 604) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 605) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 606) pde = de;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 607) de = ext2_next_entry(de);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 608) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 609) if (pde)
89e34995bdd78 (Javier Pello 2021-07-14 18:54:48 +0200 610) from = (char *)pde - kaddr;
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 611) pos = page_offset(page) + from;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 612) lock_page(page);
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 613) err = ext2_prepare_chunk(page, pos, to - from);
309be53da60dc (Eric Sesterhenn 2006-03-26 18:27:41 +0200 614) BUG_ON(err);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 615) if (pde)
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 616) pde->rec_len = ext2_rec_len_to_disk(to - from);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 617) dir->inode = 0;
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 618) err = ext2_commit_chunk(page, pos, to - from);
02027d42c3f74 (Deepa Dinamani 2016-09-14 07:48:05 -0700 619) inode->i_ctime = inode->i_mtime = current_time(inode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 620) EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 621) mark_inode_dirty(inode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 622) out:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 623) return err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 624) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 625)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 626) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 627) * Set the first fragment of directory.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 628) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 629) int ext2_make_empty(struct inode *inode, struct inode *parent)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 630) {
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 631) struct page *page = grab_cache_page(inode->i_mapping, 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 632) unsigned chunk_size = ext2_chunk_size(inode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 633) struct ext2_dir_entry_2 * de;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 634) int err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 635) void *kaddr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 636)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 637) if (!page)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 638) return -ENOMEM;
f34fb6eccc962 (Nicholas Piggin 2007-10-16 01:25:04 -0700 639)
f4e420dc42314 (Christoph Hellwig 2010-06-04 11:29:56 +0200 640) err = ext2_prepare_chunk(page, 0, chunk_size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 641) if (err) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 642) unlock_page(page);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 643) goto fail;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 644) }
d4a23aee23710 (Cong Wang 2011-11-25 23:14:29 +0800 645) kaddr = kmap_atomic(page);
7823c7c121839 (Luiz Fernando Capitulino 2006-01-11 01:38:27 +0100 646) memset(kaddr, 0, chunk_size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 647) de = (struct ext2_dir_entry_2 *)kaddr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 648) de->name_len = 1;
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 649) de->rec_len = ext2_rec_len_to_disk(EXT2_DIR_REC_LEN(1));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 650) memcpy (de->name, ".\0\0", 4);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 651) de->inode = cpu_to_le32(inode->i_ino);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 652) ext2_set_de_type (de, inode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 653)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 654) de = (struct ext2_dir_entry_2 *)(kaddr + EXT2_DIR_REC_LEN(1));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 655) de->name_len = 2;
89910cccb8fec (Jan Kara 2007-10-21 16:41:40 -0700 656) de->rec_len = ext2_rec_len_to_disk(chunk_size - EXT2_DIR_REC_LEN(1));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 657) de->inode = cpu_to_le32(parent->i_ino);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 658) memcpy (de->name, "..\0", 4);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 659) ext2_set_de_type (de, inode);
d4a23aee23710 (Cong Wang 2011-11-25 23:14:29 +0800 660) kunmap_atomic(kaddr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 661) err = ext2_commit_chunk(page, 0, chunk_size);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 662) fail:
09cbfeaf1a5a6 (Kirill A. Shutemov 2016-04-01 15:29:47 +0300 663) put_page(page);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 664) return err;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 665) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 666)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 667) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 668) * routine to check that the specified directory is empty (for rmdir)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 669) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 670) int ext2_empty_dir (struct inode * inode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 671) {
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 672) void *page_addr = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 673) struct page *page = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 674) unsigned long i, npages = dir_pages(inode);
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 675) int dir_has_error = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 676)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 677) for (i = 0; i < npages; i++) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 678) char *kaddr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 679) ext2_dirent * de;
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 680) page = ext2_get_page(inode, i, dir_has_error, &page_addr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 681)
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 682) if (IS_ERR(page)) {
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 683) dir_has_error = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 684) continue;
bd39597cbd42a (Eric Sandeen 2008-10-15 22:04:02 -0700 685) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 686)
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 687) kaddr = page_addr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 688) de = (ext2_dirent *)kaddr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 689) kaddr += ext2_last_byte(inode, i) - EXT2_DIR_REC_LEN(1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 690)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 691) while ((char *)de <= kaddr) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 692) if (de->rec_len == 0) {
605afd60ef6dd (Harvey Harrison 2008-04-28 02:16:03 -0700 693) ext2_error(inode->i_sb, __func__,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 694) "zero-length directory entry");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 695) printk("kaddr=%p, de=%p\n", kaddr, de);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 696) goto not_empty;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 697) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 698) if (de->inode != 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 699) /* check for . and .. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 700) if (de->name[0] != '.')
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 701) goto not_empty;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 702) if (de->name_len > 2)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 703) goto not_empty;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 704) if (de->name_len < 2) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 705) if (de->inode !=
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 706) cpu_to_le32(inode->i_ino))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 707) goto not_empty;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 708) } else if (de->name[1] != '.')
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 709) goto not_empty;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 710) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 711) de = ext2_next_entry(de);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 712) }
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 713) ext2_put_page(page, page_addr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 714) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 715) return 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 716)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 717) not_empty:
782b76d7abdf0 (Ira Weiny 2021-03-28 23:54:02 -0700 718) ext2_put_page(page, page_addr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 719) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 720) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 721)
4b6f5d20b04dc (Arjan van de Ven 2006-03-28 01:56:42 -0800 722) const struct file_operations ext2_dir_operations = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 723) .llseek = generic_file_llseek,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 724) .read = generic_read_dir,
3b0a3c1ac1598 (Al Viro 2016-04-20 23:42:46 -0400 725) .iterate_shared = ext2_readdir,
14f9f7b28e9f4 (Andi Kleen 2008-02-06 01:40:10 -0800 726) .unlocked_ioctl = ext2_ioctl,
e322ff07fb2d0 (David Howells 2006-08-29 19:06:20 +0100 727) #ifdef CONFIG_COMPAT
e322ff07fb2d0 (David Howells 2006-08-29 19:06:20 +0100 728) .compat_ioctl = ext2_compat_ioctl,
e322ff07fb2d0 (David Howells 2006-08-29 19:06:20 +0100 729) #endif
48bde86df0acb (Jan Kara 2009-12-15 16:46:49 -0800 730) .fsync = ext2_fsync,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 731) };