VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
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) };