xref: /linux/fs/nilfs2/dir.c (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
1ae98043fSRyusuke Konishi // SPDX-License-Identifier: GPL-2.0+
22ba466d7SYoshiji Amagai /*
394ee1d91SRyusuke Konishi  * NILFS directory entry operations
42ba466d7SYoshiji Amagai  *
52ba466d7SYoshiji Amagai  * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
62ba466d7SYoshiji Amagai  *
74b420ab4SRyusuke Konishi  * Modified for NILFS by Amagai Yoshiji.
82ba466d7SYoshiji Amagai  */
92ba466d7SYoshiji Amagai /*
102ba466d7SYoshiji Amagai  *  linux/fs/ext2/dir.c
112ba466d7SYoshiji Amagai  *
122ba466d7SYoshiji Amagai  * Copyright (C) 1992, 1993, 1994, 1995
132ba466d7SYoshiji Amagai  * Remy Card (card@masi.ibp.fr)
142ba466d7SYoshiji Amagai  * Laboratoire MASI - Institut Blaise Pascal
152ba466d7SYoshiji Amagai  * Universite Pierre et Marie Curie (Paris VI)
162ba466d7SYoshiji Amagai  *
172ba466d7SYoshiji Amagai  *  from
182ba466d7SYoshiji Amagai  *
192ba466d7SYoshiji Amagai  *  linux/fs/minix/dir.c
202ba466d7SYoshiji Amagai  *
212ba466d7SYoshiji Amagai  *  Copyright (C) 1991, 1992  Linus Torvalds
222ba466d7SYoshiji Amagai  *
232ba466d7SYoshiji Amagai  *  ext2 directory handling functions
242ba466d7SYoshiji Amagai  *
252ba466d7SYoshiji Amagai  *  Big-endian to little-endian byte-swapping/bitmaps by
262ba466d7SYoshiji Amagai  *        David S. Miller (davem@caip.rutgers.edu), 1995
272ba466d7SYoshiji Amagai  *
282ba466d7SYoshiji Amagai  * All code that works with directory layout had been switched to pagecache
292ba466d7SYoshiji Amagai  * and moved here. AV
302ba466d7SYoshiji Amagai  */
312ba466d7SYoshiji Amagai 
322ba466d7SYoshiji Amagai #include <linux/pagemap.h>
332ba466d7SYoshiji Amagai #include "nilfs.h"
342ba466d7SYoshiji Amagai #include "page.h"
352ba466d7SYoshiji Amagai 
36e63e88bcSRyusuke Konishi static inline unsigned int nilfs_rec_len_from_disk(__le16 dlen)
37e63e88bcSRyusuke Konishi {
38e63e88bcSRyusuke Konishi 	unsigned int len = le16_to_cpu(dlen);
39e63e88bcSRyusuke Konishi 
40e63e88bcSRyusuke Konishi #if (PAGE_SIZE >= 65536)
41e63e88bcSRyusuke Konishi 	if (len == NILFS_MAX_REC_LEN)
42e63e88bcSRyusuke Konishi 		return 1 << 16;
43e63e88bcSRyusuke Konishi #endif
44e63e88bcSRyusuke Konishi 	return len;
45e63e88bcSRyusuke Konishi }
46e63e88bcSRyusuke Konishi 
47e63e88bcSRyusuke Konishi static inline __le16 nilfs_rec_len_to_disk(unsigned int len)
48e63e88bcSRyusuke Konishi {
49e63e88bcSRyusuke Konishi #if (PAGE_SIZE >= 65536)
50e63e88bcSRyusuke Konishi 	if (len == (1 << 16))
51e63e88bcSRyusuke Konishi 		return cpu_to_le16(NILFS_MAX_REC_LEN);
52e63e88bcSRyusuke Konishi 
53e63e88bcSRyusuke Konishi 	BUG_ON(len > (1 << 16));
54e63e88bcSRyusuke Konishi #endif
55e63e88bcSRyusuke Konishi 	return cpu_to_le16(len);
56e63e88bcSRyusuke Konishi }
57e63e88bcSRyusuke Konishi 
582ba466d7SYoshiji Amagai /*
592ba466d7SYoshiji Amagai  * nilfs uses block-sized chunks. Arguably, sector-sized ones would be
602ba466d7SYoshiji Amagai  * more robust, but we have what we have
612ba466d7SYoshiji Amagai  */
620c6c44cbSRyusuke Konishi static inline unsigned int nilfs_chunk_size(struct inode *inode)
632ba466d7SYoshiji Amagai {
642ba466d7SYoshiji Amagai 	return inode->i_sb->s_blocksize;
652ba466d7SYoshiji Amagai }
662ba466d7SYoshiji Amagai 
672ba466d7SYoshiji Amagai /*
682ba466d7SYoshiji Amagai  * Return the offset into page `page_nr' of the last valid
692ba466d7SYoshiji Amagai  * byte in that page, plus one.
702ba466d7SYoshiji Amagai  */
710c6c44cbSRyusuke Konishi static unsigned int nilfs_last_byte(struct inode *inode, unsigned long page_nr)
722ba466d7SYoshiji Amagai {
730c6c44cbSRyusuke Konishi 	unsigned int last_byte = inode->i_size;
742ba466d7SYoshiji Amagai 
7509cbfeafSKirill A. Shutemov 	last_byte -= page_nr << PAGE_SHIFT;
7609cbfeafSKirill A. Shutemov 	if (last_byte > PAGE_SIZE)
7709cbfeafSKirill A. Shutemov 		last_byte = PAGE_SIZE;
782ba466d7SYoshiji Amagai 	return last_byte;
792ba466d7SYoshiji Amagai }
802ba466d7SYoshiji Amagai 
819bff5f98SMatthew Wilcox (Oracle) static int nilfs_prepare_chunk(struct folio *folio, unsigned int from,
820c6c44cbSRyusuke Konishi 			       unsigned int to)
832ba466d7SYoshiji Amagai {
849bff5f98SMatthew Wilcox (Oracle) 	loff_t pos = folio_pos(folio) + from;
854ad364caSRyusuke Konishi 
869bff5f98SMatthew Wilcox (Oracle) 	return __block_write_begin(&folio->page, pos, to - from, nilfs_get_block);
872ba466d7SYoshiji Amagai }
882ba466d7SYoshiji Amagai 
899bff5f98SMatthew Wilcox (Oracle) static void nilfs_commit_chunk(struct folio *folio,
909bff5f98SMatthew Wilcox (Oracle) 		struct address_space *mapping, size_t from, size_t to)
912ba466d7SYoshiji Amagai {
922ba466d7SYoshiji Amagai 	struct inode *dir = mapping->host;
939bff5f98SMatthew Wilcox (Oracle) 	loff_t pos = folio_pos(folio) + from;
949bff5f98SMatthew Wilcox (Oracle) 	size_t copied, len = to - from;
959bff5f98SMatthew Wilcox (Oracle) 	unsigned int nr_dirty;
962ba466d7SYoshiji Amagai 	int err;
972ba466d7SYoshiji Amagai 
989bff5f98SMatthew Wilcox (Oracle) 	nr_dirty = nilfs_page_count_clean_buffers(&folio->page, from, to);
999bff5f98SMatthew Wilcox (Oracle) 	copied = block_write_end(NULL, mapping, pos, len, len, &folio->page, NULL);
10058d55471SJiro SEKIBA 	if (pos + copied > dir->i_size)
1012ba466d7SYoshiji Amagai 		i_size_write(dir, pos + copied);
1022ba466d7SYoshiji Amagai 	if (IS_DIRSYNC(dir))
1032ba466d7SYoshiji Amagai 		nilfs_set_transaction_flag(NILFS_TI_SYNC);
104bcbc8c64SRyusuke Konishi 	err = nilfs_set_file_dirty(dir, nr_dirty);
1052093abf9SJiro SEKIBA 	WARN_ON(err); /* do not happen */
1069bff5f98SMatthew Wilcox (Oracle) 	folio_unlock(folio);
1072ba466d7SYoshiji Amagai }
1082ba466d7SYoshiji Amagai 
10975ad5db6SMatthew Wilcox (Oracle) static bool nilfs_check_folio(struct folio *folio, char *kaddr)
1102ba466d7SYoshiji Amagai {
11175ad5db6SMatthew Wilcox (Oracle) 	struct inode *dir = folio->mapping->host;
1122ba466d7SYoshiji Amagai 	struct super_block *sb = dir->i_sb;
1130c6c44cbSRyusuke Konishi 	unsigned int chunk_size = nilfs_chunk_size(dir);
11475ad5db6SMatthew Wilcox (Oracle) 	size_t offs, rec_len;
11575ad5db6SMatthew Wilcox (Oracle) 	size_t limit = folio_size(folio);
1162ba466d7SYoshiji Amagai 	struct nilfs_dir_entry *p;
1172ba466d7SYoshiji Amagai 	char *error;
1182ba466d7SYoshiji Amagai 
11975ad5db6SMatthew Wilcox (Oracle) 	if (dir->i_size < folio_pos(folio) + limit) {
12075ad5db6SMatthew Wilcox (Oracle) 		limit = dir->i_size - folio_pos(folio);
1212ba466d7SYoshiji Amagai 		if (limit & (chunk_size - 1))
1222ba466d7SYoshiji Amagai 			goto Ebadsize;
1232ba466d7SYoshiji Amagai 		if (!limit)
1242ba466d7SYoshiji Amagai 			goto out;
1252ba466d7SYoshiji Amagai 	}
1262ba466d7SYoshiji Amagai 	for (offs = 0; offs <= limit - NILFS_DIR_REC_LEN(1); offs += rec_len) {
1272ba466d7SYoshiji Amagai 		p = (struct nilfs_dir_entry *)(kaddr + offs);
1286cda9fa2SRyusuke Konishi 		rec_len = nilfs_rec_len_from_disk(p->rec_len);
1292ba466d7SYoshiji Amagai 
1302ba466d7SYoshiji Amagai 		if (rec_len < NILFS_DIR_REC_LEN(1))
1312ba466d7SYoshiji Amagai 			goto Eshort;
1322ba466d7SYoshiji Amagai 		if (rec_len & 3)
1332ba466d7SYoshiji Amagai 			goto Ealign;
1342ba466d7SYoshiji Amagai 		if (rec_len < NILFS_DIR_REC_LEN(p->name_len))
1352ba466d7SYoshiji Amagai 			goto Enamelen;
1362ba466d7SYoshiji Amagai 		if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))
1372ba466d7SYoshiji Amagai 			goto Espan;
138bb76c6c2SRyusuke Konishi 		if (unlikely(p->inode &&
139bb76c6c2SRyusuke Konishi 			     NILFS_PRIVATE_INODE(le64_to_cpu(p->inode))))
140bb76c6c2SRyusuke Konishi 			goto Einumber;
1412ba466d7SYoshiji Amagai 	}
1422ba466d7SYoshiji Amagai 	if (offs != limit)
1432ba466d7SYoshiji Amagai 		goto Eend;
1442ba466d7SYoshiji Amagai out:
14575ad5db6SMatthew Wilcox (Oracle) 	folio_set_checked(folio);
146be5b82dbSAl Viro 	return true;
1472ba466d7SYoshiji Amagai 
1482ba466d7SYoshiji Amagai 	/* Too bad, we had an error */
1492ba466d7SYoshiji Amagai 
1502ba466d7SYoshiji Amagai Ebadsize:
151cae3d4caSRyusuke Konishi 	nilfs_error(sb,
1522ba466d7SYoshiji Amagai 		    "size of directory #%lu is not a multiple of chunk size",
153cae3d4caSRyusuke Konishi 		    dir->i_ino);
1542ba466d7SYoshiji Amagai 	goto fail;
1552ba466d7SYoshiji Amagai Eshort:
1562ba466d7SYoshiji Amagai 	error = "rec_len is smaller than minimal";
1572ba466d7SYoshiji Amagai 	goto bad_entry;
1582ba466d7SYoshiji Amagai Ealign:
1592ba466d7SYoshiji Amagai 	error = "unaligned directory entry";
1602ba466d7SYoshiji Amagai 	goto bad_entry;
1612ba466d7SYoshiji Amagai Enamelen:
1622ba466d7SYoshiji Amagai 	error = "rec_len is too small for name_len";
1632ba466d7SYoshiji Amagai 	goto bad_entry;
1642ba466d7SYoshiji Amagai Espan:
1652ba466d7SYoshiji Amagai 	error = "directory entry across blocks";
166bb76c6c2SRyusuke Konishi 	goto bad_entry;
167bb76c6c2SRyusuke Konishi Einumber:
168bb76c6c2SRyusuke Konishi 	error = "disallowed inode number";
1692ba466d7SYoshiji Amagai bad_entry:
170cae3d4caSRyusuke Konishi 	nilfs_error(sb,
17175ad5db6SMatthew Wilcox (Oracle) 		    "bad entry in directory #%lu: %s - offset=%lu, inode=%lu, rec_len=%zd, name_len=%d",
17275ad5db6SMatthew Wilcox (Oracle) 		    dir->i_ino, error, (folio->index << PAGE_SHIFT) + offs,
1732ba466d7SYoshiji Amagai 		    (unsigned long)le64_to_cpu(p->inode),
1742ba466d7SYoshiji Amagai 		    rec_len, p->name_len);
1752ba466d7SYoshiji Amagai 	goto fail;
1762ba466d7SYoshiji Amagai Eend:
1772ba466d7SYoshiji Amagai 	p = (struct nilfs_dir_entry *)(kaddr + offs);
178cae3d4caSRyusuke Konishi 	nilfs_error(sb,
179cae3d4caSRyusuke Konishi 		    "entry in directory #%lu spans the page boundary offset=%lu, inode=%lu",
18075ad5db6SMatthew Wilcox (Oracle) 		    dir->i_ino, (folio->index << PAGE_SHIFT) + offs,
1812ba466d7SYoshiji Amagai 		    (unsigned long)le64_to_cpu(p->inode));
1822ba466d7SYoshiji Amagai fail:
183be5b82dbSAl Viro 	return false;
1842ba466d7SYoshiji Amagai }
1852ba466d7SYoshiji Amagai 
18675ad5db6SMatthew Wilcox (Oracle) static void *nilfs_get_folio(struct inode *dir, unsigned long n,
18775ad5db6SMatthew Wilcox (Oracle) 		struct folio **foliop)
18875ad5db6SMatthew Wilcox (Oracle) {
18975ad5db6SMatthew Wilcox (Oracle) 	struct address_space *mapping = dir->i_mapping;
19075ad5db6SMatthew Wilcox (Oracle) 	struct folio *folio = read_mapping_folio(mapping, n, NULL);
19175ad5db6SMatthew Wilcox (Oracle) 	void *kaddr;
19275ad5db6SMatthew Wilcox (Oracle) 
19375ad5db6SMatthew Wilcox (Oracle) 	if (IS_ERR(folio))
19475ad5db6SMatthew Wilcox (Oracle) 		return folio;
19575ad5db6SMatthew Wilcox (Oracle) 
19675ad5db6SMatthew Wilcox (Oracle) 	kaddr = kmap_local_folio(folio, 0);
19775ad5db6SMatthew Wilcox (Oracle) 	if (unlikely(!folio_test_checked(folio))) {
19875ad5db6SMatthew Wilcox (Oracle) 		if (!nilfs_check_folio(folio, kaddr))
19975ad5db6SMatthew Wilcox (Oracle) 			goto fail;
20075ad5db6SMatthew Wilcox (Oracle) 	}
20175ad5db6SMatthew Wilcox (Oracle) 
20275ad5db6SMatthew Wilcox (Oracle) 	*foliop = folio;
20375ad5db6SMatthew Wilcox (Oracle) 	return kaddr;
20475ad5db6SMatthew Wilcox (Oracle) 
20575ad5db6SMatthew Wilcox (Oracle) fail:
20675ad5db6SMatthew Wilcox (Oracle) 	folio_release_kmap(folio, kaddr);
20775ad5db6SMatthew Wilcox (Oracle) 	return ERR_PTR(-EIO);
20875ad5db6SMatthew Wilcox (Oracle) }
20975ad5db6SMatthew Wilcox (Oracle) 
2102ba466d7SYoshiji Amagai /*
2112ba466d7SYoshiji Amagai  * NOTE! unlike strncmp, nilfs_match returns 1 for success, 0 for failure.
2122ba466d7SYoshiji Amagai  *
2132ba466d7SYoshiji Amagai  * len <= NILFS_NAME_LEN and de != NULL are guaranteed by caller.
2142ba466d7SYoshiji Amagai  */
2152ba466d7SYoshiji Amagai static int
216072f98b4SAl Viro nilfs_match(int len, const unsigned char *name, struct nilfs_dir_entry *de)
2172ba466d7SYoshiji Amagai {
2182ba466d7SYoshiji Amagai 	if (len != de->name_len)
2192ba466d7SYoshiji Amagai 		return 0;
2202ba466d7SYoshiji Amagai 	if (!de->inode)
2212ba466d7SYoshiji Amagai 		return 0;
2222ba466d7SYoshiji Amagai 	return !memcmp(name, de->name, len);
2232ba466d7SYoshiji Amagai }
2242ba466d7SYoshiji Amagai 
2252ba466d7SYoshiji Amagai /*
2262ba466d7SYoshiji Amagai  * p is at least 6 bytes before the end of page
2272ba466d7SYoshiji Amagai  */
2282ba466d7SYoshiji Amagai static struct nilfs_dir_entry *nilfs_next_entry(struct nilfs_dir_entry *p)
2292ba466d7SYoshiji Amagai {
2306cda9fa2SRyusuke Konishi 	return (struct nilfs_dir_entry *)((char *)p +
2316cda9fa2SRyusuke Konishi 					  nilfs_rec_len_from_disk(p->rec_len));
2322ba466d7SYoshiji Amagai }
2332ba466d7SYoshiji Amagai 
2342ba466d7SYoshiji Amagai static unsigned char
2352ba466d7SYoshiji Amagai nilfs_filetype_table[NILFS_FT_MAX] = {
2362ba466d7SYoshiji Amagai 	[NILFS_FT_UNKNOWN]	= DT_UNKNOWN,
2372ba466d7SYoshiji Amagai 	[NILFS_FT_REG_FILE]	= DT_REG,
2382ba466d7SYoshiji Amagai 	[NILFS_FT_DIR]		= DT_DIR,
2392ba466d7SYoshiji Amagai 	[NILFS_FT_CHRDEV]	= DT_CHR,
2402ba466d7SYoshiji Amagai 	[NILFS_FT_BLKDEV]	= DT_BLK,
2412ba466d7SYoshiji Amagai 	[NILFS_FT_FIFO]		= DT_FIFO,
2422ba466d7SYoshiji Amagai 	[NILFS_FT_SOCK]		= DT_SOCK,
2432ba466d7SYoshiji Amagai 	[NILFS_FT_SYMLINK]	= DT_LNK,
2442ba466d7SYoshiji Amagai };
2452ba466d7SYoshiji Amagai 
2462ba466d7SYoshiji Amagai #define S_SHIFT 12
2472ba466d7SYoshiji Amagai static unsigned char
248c4a7dc95SJeongjun Park nilfs_type_by_mode[(S_IFMT >> S_SHIFT) + 1] = {
2492ba466d7SYoshiji Amagai 	[S_IFREG >> S_SHIFT]	= NILFS_FT_REG_FILE,
2502ba466d7SYoshiji Amagai 	[S_IFDIR >> S_SHIFT]	= NILFS_FT_DIR,
2512ba466d7SYoshiji Amagai 	[S_IFCHR >> S_SHIFT]	= NILFS_FT_CHRDEV,
2522ba466d7SYoshiji Amagai 	[S_IFBLK >> S_SHIFT]	= NILFS_FT_BLKDEV,
2532ba466d7SYoshiji Amagai 	[S_IFIFO >> S_SHIFT]	= NILFS_FT_FIFO,
2542ba466d7SYoshiji Amagai 	[S_IFSOCK >> S_SHIFT]	= NILFS_FT_SOCK,
2552ba466d7SYoshiji Amagai 	[S_IFLNK >> S_SHIFT]	= NILFS_FT_SYMLINK,
2562ba466d7SYoshiji Amagai };
2572ba466d7SYoshiji Amagai 
2582ba466d7SYoshiji Amagai static void nilfs_set_de_type(struct nilfs_dir_entry *de, struct inode *inode)
2592ba466d7SYoshiji Amagai {
260c6e49e3fSAl Viro 	umode_t mode = inode->i_mode;
2612ba466d7SYoshiji Amagai 
2622ba466d7SYoshiji Amagai 	de->file_type = nilfs_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
2632ba466d7SYoshiji Amagai }
2642ba466d7SYoshiji Amagai 
2651616abe8SAl Viro static int nilfs_readdir(struct file *file, struct dir_context *ctx)
2662ba466d7SYoshiji Amagai {
2671616abe8SAl Viro 	loff_t pos = ctx->pos;
2681616abe8SAl Viro 	struct inode *inode = file_inode(file);
2692ba466d7SYoshiji Amagai 	struct super_block *sb = inode->i_sb;
27009cbfeafSKirill A. Shutemov 	unsigned int offset = pos & ~PAGE_MASK;
27109cbfeafSKirill A. Shutemov 	unsigned long n = pos >> PAGE_SHIFT;
2722ba466d7SYoshiji Amagai 	unsigned long npages = dir_pages(inode);
2732ba466d7SYoshiji Amagai 
2742ba466d7SYoshiji Amagai 	if (pos > inode->i_size - NILFS_DIR_REC_LEN(1))
2751616abe8SAl Viro 		return 0;
2762ba466d7SYoshiji Amagai 
2772ba466d7SYoshiji Amagai 	for ( ; n < npages; n++, offset = 0) {
2782ba466d7SYoshiji Amagai 		char *kaddr, *limit;
2792ba466d7SYoshiji Amagai 		struct nilfs_dir_entry *de;
280b37b2becSMatthew Wilcox (Oracle) 		struct folio *folio;
2812ba466d7SYoshiji Amagai 
282b37b2becSMatthew Wilcox (Oracle) 		kaddr = nilfs_get_folio(inode, n, &folio);
28309a46acbSMatthew Wilcox (Oracle) 		if (IS_ERR(kaddr)) {
284cae3d4caSRyusuke Konishi 			nilfs_error(sb, "bad page in #%lu", inode->i_ino);
28509cbfeafSKirill A. Shutemov 			ctx->pos += PAGE_SIZE - offset;
2861616abe8SAl Viro 			return -EIO;
2872ba466d7SYoshiji Amagai 		}
2882ba466d7SYoshiji Amagai 		de = (struct nilfs_dir_entry *)(kaddr + offset);
2892ba466d7SYoshiji Amagai 		limit = kaddr + nilfs_last_byte(inode, n) -
2902ba466d7SYoshiji Amagai 			NILFS_DIR_REC_LEN(1);
2912ba466d7SYoshiji Amagai 		for ( ; (char *)de <= limit; de = nilfs_next_entry(de)) {
2922ba466d7SYoshiji Amagai 			if (de->rec_len == 0) {
293cae3d4caSRyusuke Konishi 				nilfs_error(sb, "zero-length directory entry");
294b37b2becSMatthew Wilcox (Oracle) 				folio_release_kmap(folio, kaddr);
2951616abe8SAl Viro 				return -EIO;
2962ba466d7SYoshiji Amagai 			}
2972ba466d7SYoshiji Amagai 			if (de->inode) {
2981616abe8SAl Viro 				unsigned char t;
2992ba466d7SYoshiji Amagai 
3001616abe8SAl Viro 				if (de->file_type < NILFS_FT_MAX)
3011616abe8SAl Viro 					t = nilfs_filetype_table[de->file_type];
3021616abe8SAl Viro 				else
3031616abe8SAl Viro 					t = DT_UNKNOWN;
3042ba466d7SYoshiji Amagai 
3051616abe8SAl Viro 				if (!dir_emit(ctx, de->name, de->name_len,
3061616abe8SAl Viro 						le64_to_cpu(de->inode), t)) {
307b37b2becSMatthew Wilcox (Oracle) 					folio_release_kmap(folio, kaddr);
3081616abe8SAl Viro 					return 0;
3092ba466d7SYoshiji Amagai 				}
3102ba466d7SYoshiji Amagai 			}
3111616abe8SAl Viro 			ctx->pos += nilfs_rec_len_from_disk(de->rec_len);
3122ba466d7SYoshiji Amagai 		}
313b37b2becSMatthew Wilcox (Oracle) 		folio_release_kmap(folio, kaddr);
3142ba466d7SYoshiji Amagai 	}
3151616abe8SAl Viro 	return 0;
3162ba466d7SYoshiji Amagai }
3172ba466d7SYoshiji Amagai 
3182ba466d7SYoshiji Amagai /*
3192ba466d7SYoshiji Amagai  * nilfs_find_entry()
3202ba466d7SYoshiji Amagai  *
3216f133c97SMatthew Wilcox (Oracle)  * Finds an entry in the specified directory with the wanted name. It
3226f133c97SMatthew Wilcox (Oracle)  * returns the folio in which the entry was found, and the entry itself.
3236f133c97SMatthew Wilcox (Oracle)  * The folio is mapped and unlocked.  When the caller is finished with
3246f133c97SMatthew Wilcox (Oracle)  * the entry, it should call folio_release_kmap().
3256f133c97SMatthew Wilcox (Oracle)  *
3266f133c97SMatthew Wilcox (Oracle)  * On failure, returns NULL and the caller should ignore foliop.
3272ba466d7SYoshiji Amagai  */
3286f133c97SMatthew Wilcox (Oracle) struct nilfs_dir_entry *nilfs_find_entry(struct inode *dir,
3296f133c97SMatthew Wilcox (Oracle) 		const struct qstr *qstr, struct folio **foliop)
3302ba466d7SYoshiji Amagai {
3310319003dSAl Viro 	const unsigned char *name = qstr->name;
3320319003dSAl Viro 	int namelen = qstr->len;
3330c6c44cbSRyusuke Konishi 	unsigned int reclen = NILFS_DIR_REC_LEN(namelen);
3342ba466d7SYoshiji Amagai 	unsigned long start, n;
3352ba466d7SYoshiji Amagai 	unsigned long npages = dir_pages(dir);
3362ba466d7SYoshiji Amagai 	struct nilfs_inode_info *ei = NILFS_I(dir);
3372ba466d7SYoshiji Amagai 	struct nilfs_dir_entry *de;
3382ba466d7SYoshiji Amagai 
3392ba466d7SYoshiji Amagai 	if (npages == 0)
3402ba466d7SYoshiji Amagai 		goto out;
3412ba466d7SYoshiji Amagai 
3422ba466d7SYoshiji Amagai 	start = ei->i_dir_start_lookup;
3432ba466d7SYoshiji Amagai 	if (start >= npages)
3442ba466d7SYoshiji Amagai 		start = 0;
3452ba466d7SYoshiji Amagai 	n = start;
3462ba466d7SYoshiji Amagai 	do {
3476f133c97SMatthew Wilcox (Oracle) 		char *kaddr = nilfs_get_folio(dir, n, foliop);
3484ad364caSRyusuke Konishi 
34909a46acbSMatthew Wilcox (Oracle) 		if (!IS_ERR(kaddr)) {
3502ba466d7SYoshiji Amagai 			de = (struct nilfs_dir_entry *)kaddr;
3512ba466d7SYoshiji Amagai 			kaddr += nilfs_last_byte(dir, n) - reclen;
3522ba466d7SYoshiji Amagai 			while ((char *) de <= kaddr) {
3532ba466d7SYoshiji Amagai 				if (de->rec_len == 0) {
354cae3d4caSRyusuke Konishi 					nilfs_error(dir->i_sb,
3552ba466d7SYoshiji Amagai 						"zero-length directory entry");
3566f133c97SMatthew Wilcox (Oracle) 					folio_release_kmap(*foliop, kaddr);
3572ba466d7SYoshiji Amagai 					goto out;
3582ba466d7SYoshiji Amagai 				}
3592ba466d7SYoshiji Amagai 				if (nilfs_match(namelen, name, de))
3602ba466d7SYoshiji Amagai 					goto found;
3612ba466d7SYoshiji Amagai 				de = nilfs_next_entry(de);
3622ba466d7SYoshiji Amagai 			}
3636f133c97SMatthew Wilcox (Oracle) 			folio_release_kmap(*foliop, kaddr);
3642ba466d7SYoshiji Amagai 		}
3652ba466d7SYoshiji Amagai 		if (++n >= npages)
3662ba466d7SYoshiji Amagai 			n = 0;
367a4bf041eSMatthew Wilcox (Oracle) 		/* next folio is past the blocks we've got */
36809cbfeafSKirill A. Shutemov 		if (unlikely(n > (dir->i_blocks >> (PAGE_SHIFT - 9)))) {
369cae3d4caSRyusuke Konishi 			nilfs_error(dir->i_sb,
3701621562bSRyusuke Konishi 			       "dir %lu size %lld exceeds block count %llu",
3712ba466d7SYoshiji Amagai 			       dir->i_ino, dir->i_size,
3722ba466d7SYoshiji Amagai 			       (unsigned long long)dir->i_blocks);
3732ba466d7SYoshiji Amagai 			goto out;
3742ba466d7SYoshiji Amagai 		}
3752ba466d7SYoshiji Amagai 	} while (n != start);
3762ba466d7SYoshiji Amagai out:
3772ba466d7SYoshiji Amagai 	return NULL;
3782ba466d7SYoshiji Amagai 
3792ba466d7SYoshiji Amagai found:
3802ba466d7SYoshiji Amagai 	ei->i_dir_start_lookup = n;
3812ba466d7SYoshiji Amagai 	return de;
3822ba466d7SYoshiji Amagai }
3832ba466d7SYoshiji Amagai 
3846f133c97SMatthew Wilcox (Oracle) struct nilfs_dir_entry *nilfs_dotdot(struct inode *dir, struct folio **foliop)
3852ba466d7SYoshiji Amagai {
386*a9e1ddc0SRyusuke Konishi 	struct folio *folio;
387*a9e1ddc0SRyusuke Konishi 	struct nilfs_dir_entry *de, *next_de;
388*a9e1ddc0SRyusuke Konishi 	size_t limit;
389*a9e1ddc0SRyusuke Konishi 	char *msg;
3902ba466d7SYoshiji Amagai 
391*a9e1ddc0SRyusuke Konishi 	de = nilfs_get_folio(dir, 0, &folio);
39209a46acbSMatthew Wilcox (Oracle) 	if (IS_ERR(de))
39309a46acbSMatthew Wilcox (Oracle) 		return NULL;
394*a9e1ddc0SRyusuke Konishi 
395*a9e1ddc0SRyusuke Konishi 	limit = nilfs_last_byte(dir, 0);  /* is a multiple of chunk size */
396*a9e1ddc0SRyusuke Konishi 	if (unlikely(!limit || le64_to_cpu(de->inode) != dir->i_ino ||
397*a9e1ddc0SRyusuke Konishi 		     !nilfs_match(1, ".", de))) {
398*a9e1ddc0SRyusuke Konishi 		msg = "missing '.'";
399*a9e1ddc0SRyusuke Konishi 		goto fail;
400*a9e1ddc0SRyusuke Konishi 	}
401*a9e1ddc0SRyusuke Konishi 
402*a9e1ddc0SRyusuke Konishi 	next_de = nilfs_next_entry(de);
403*a9e1ddc0SRyusuke Konishi 	/*
404*a9e1ddc0SRyusuke Konishi 	 * If "next_de" has not reached the end of the chunk, there is
405*a9e1ddc0SRyusuke Konishi 	 * at least one more record.  Check whether it matches "..".
406*a9e1ddc0SRyusuke Konishi 	 */
407*a9e1ddc0SRyusuke Konishi 	if (unlikely((char *)next_de == (char *)de + nilfs_chunk_size(dir) ||
408*a9e1ddc0SRyusuke Konishi 		     !nilfs_match(2, "..", next_de))) {
409*a9e1ddc0SRyusuke Konishi 		msg = "missing '..'";
410*a9e1ddc0SRyusuke Konishi 		goto fail;
411*a9e1ddc0SRyusuke Konishi 	}
412*a9e1ddc0SRyusuke Konishi 	*foliop = folio;
413*a9e1ddc0SRyusuke Konishi 	return next_de;
414*a9e1ddc0SRyusuke Konishi 
415*a9e1ddc0SRyusuke Konishi fail:
416*a9e1ddc0SRyusuke Konishi 	nilfs_error(dir->i_sb, "directory #%lu %s", dir->i_ino, msg);
417*a9e1ddc0SRyusuke Konishi 	folio_release_kmap(folio, de);
418*a9e1ddc0SRyusuke Konishi 	return NULL;
4192ba466d7SYoshiji Amagai }
4202ba466d7SYoshiji Amagai 
4210319003dSAl Viro ino_t nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr)
4222ba466d7SYoshiji Amagai {
4232ba466d7SYoshiji Amagai 	ino_t res = 0;
4242ba466d7SYoshiji Amagai 	struct nilfs_dir_entry *de;
4256f133c97SMatthew Wilcox (Oracle) 	struct folio *folio;
4262ba466d7SYoshiji Amagai 
4276f133c97SMatthew Wilcox (Oracle) 	de = nilfs_find_entry(dir, qstr, &folio);
4282ba466d7SYoshiji Amagai 	if (de) {
4292ba466d7SYoshiji Amagai 		res = le64_to_cpu(de->inode);
4306f133c97SMatthew Wilcox (Oracle) 		folio_release_kmap(folio, de);
4312ba466d7SYoshiji Amagai 	}
4322ba466d7SYoshiji Amagai 	return res;
4332ba466d7SYoshiji Amagai }
4342ba466d7SYoshiji Amagai 
4352ba466d7SYoshiji Amagai void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
4366f133c97SMatthew Wilcox (Oracle) 		    struct folio *folio, struct inode *inode)
4372ba466d7SYoshiji Amagai {
4386f133c97SMatthew Wilcox (Oracle) 	size_t from = offset_in_folio(folio, de);
4396f133c97SMatthew Wilcox (Oracle) 	size_t to = from + nilfs_rec_len_from_disk(de->rec_len);
4406f133c97SMatthew Wilcox (Oracle) 	struct address_space *mapping = folio->mapping;
4412ba466d7SYoshiji Amagai 	int err;
4422ba466d7SYoshiji Amagai 
4436f133c97SMatthew Wilcox (Oracle) 	folio_lock(folio);
4449bff5f98SMatthew Wilcox (Oracle) 	err = nilfs_prepare_chunk(folio, from, to);
4452ba466d7SYoshiji Amagai 	BUG_ON(err);
4462ba466d7SYoshiji Amagai 	de->inode = cpu_to_le64(inode->i_ino);
4472ba466d7SYoshiji Amagai 	nilfs_set_de_type(de, inode);
4489bff5f98SMatthew Wilcox (Oracle) 	nilfs_commit_chunk(folio, mapping, from, to);
449b3e1cc39SJeff Layton 	inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
4502ba466d7SYoshiji Amagai }
4512ba466d7SYoshiji Amagai 
4522ba466d7SYoshiji Amagai /*
4532ba466d7SYoshiji Amagai  *	Parent is locked.
4542ba466d7SYoshiji Amagai  */
4552ba466d7SYoshiji Amagai int nilfs_add_link(struct dentry *dentry, struct inode *inode)
4562ba466d7SYoshiji Amagai {
4572b0143b5SDavid Howells 	struct inode *dir = d_inode(dentry->d_parent);
458072f98b4SAl Viro 	const unsigned char *name = dentry->d_name.name;
4592ba466d7SYoshiji Amagai 	int namelen = dentry->d_name.len;
4600c6c44cbSRyusuke Konishi 	unsigned int chunk_size = nilfs_chunk_size(dir);
4610c6c44cbSRyusuke Konishi 	unsigned int reclen = NILFS_DIR_REC_LEN(namelen);
4622ba466d7SYoshiji Amagai 	unsigned short rec_len, name_len;
463f59bb60fSMatthew Wilcox (Oracle) 	struct folio *folio = NULL;
4642ba466d7SYoshiji Amagai 	struct nilfs_dir_entry *de;
4652ba466d7SYoshiji Amagai 	unsigned long npages = dir_pages(dir);
4662ba466d7SYoshiji Amagai 	unsigned long n;
467f59bb60fSMatthew Wilcox (Oracle) 	size_t from, to;
4682ba466d7SYoshiji Amagai 	int err;
4692ba466d7SYoshiji Amagai 
4702ba466d7SYoshiji Amagai 	/*
4712ba466d7SYoshiji Amagai 	 * We take care of directory expansion in the same loop.
472f59bb60fSMatthew Wilcox (Oracle) 	 * This code plays outside i_size, so it locks the folio
4732ba466d7SYoshiji Amagai 	 * to protect that region.
4742ba466d7SYoshiji Amagai 	 */
4752ba466d7SYoshiji Amagai 	for (n = 0; n <= npages; n++) {
476f59bb60fSMatthew Wilcox (Oracle) 		char *kaddr = nilfs_get_folio(dir, n, &folio);
4772ba466d7SYoshiji Amagai 		char *dir_end;
4782ba466d7SYoshiji Amagai 
47909a46acbSMatthew Wilcox (Oracle) 		if (IS_ERR(kaddr))
480f59bb60fSMatthew Wilcox (Oracle) 			return PTR_ERR(kaddr);
481f59bb60fSMatthew Wilcox (Oracle) 		folio_lock(folio);
4822ba466d7SYoshiji Amagai 		dir_end = kaddr + nilfs_last_byte(dir, n);
4832ba466d7SYoshiji Amagai 		de = (struct nilfs_dir_entry *)kaddr;
484f59bb60fSMatthew Wilcox (Oracle) 		kaddr += folio_size(folio) - reclen;
4852ba466d7SYoshiji Amagai 		while ((char *)de <= kaddr) {
4862ba466d7SYoshiji Amagai 			if ((char *)de == dir_end) {
4872ba466d7SYoshiji Amagai 				/* We hit i_size */
4882ba466d7SYoshiji Amagai 				name_len = 0;
4892ba466d7SYoshiji Amagai 				rec_len = chunk_size;
4906cda9fa2SRyusuke Konishi 				de->rec_len = nilfs_rec_len_to_disk(chunk_size);
4912ba466d7SYoshiji Amagai 				de->inode = 0;
4922ba466d7SYoshiji Amagai 				goto got_it;
4932ba466d7SYoshiji Amagai 			}
4942ba466d7SYoshiji Amagai 			if (de->rec_len == 0) {
495cae3d4caSRyusuke Konishi 				nilfs_error(dir->i_sb,
4962ba466d7SYoshiji Amagai 					    "zero-length directory entry");
4972ba466d7SYoshiji Amagai 				err = -EIO;
4982ba466d7SYoshiji Amagai 				goto out_unlock;
4992ba466d7SYoshiji Amagai 			}
5002ba466d7SYoshiji Amagai 			err = -EEXIST;
5012ba466d7SYoshiji Amagai 			if (nilfs_match(namelen, name, de))
5022ba466d7SYoshiji Amagai 				goto out_unlock;
5032ba466d7SYoshiji Amagai 			name_len = NILFS_DIR_REC_LEN(de->name_len);
5046cda9fa2SRyusuke Konishi 			rec_len = nilfs_rec_len_from_disk(de->rec_len);
5052ba466d7SYoshiji Amagai 			if (!de->inode && rec_len >= reclen)
5062ba466d7SYoshiji Amagai 				goto got_it;
5072ba466d7SYoshiji Amagai 			if (rec_len >= name_len + reclen)
5082ba466d7SYoshiji Amagai 				goto got_it;
5092ba466d7SYoshiji Amagai 			de = (struct nilfs_dir_entry *)((char *)de + rec_len);
5102ba466d7SYoshiji Amagai 		}
511f59bb60fSMatthew Wilcox (Oracle) 		folio_unlock(folio);
512f59bb60fSMatthew Wilcox (Oracle) 		folio_release_kmap(folio, kaddr);
5132ba466d7SYoshiji Amagai 	}
5142ba466d7SYoshiji Amagai 	BUG();
5152ba466d7SYoshiji Amagai 	return -EINVAL;
5162ba466d7SYoshiji Amagai 
5172ba466d7SYoshiji Amagai got_it:
518f59bb60fSMatthew Wilcox (Oracle) 	from = offset_in_folio(folio, de);
5192ba466d7SYoshiji Amagai 	to = from + rec_len;
5209bff5f98SMatthew Wilcox (Oracle) 	err = nilfs_prepare_chunk(folio, from, to);
5212ba466d7SYoshiji Amagai 	if (err)
5222ba466d7SYoshiji Amagai 		goto out_unlock;
5232ba466d7SYoshiji Amagai 	if (de->inode) {
5242ba466d7SYoshiji Amagai 		struct nilfs_dir_entry *de1;
5252ba466d7SYoshiji Amagai 
5262ba466d7SYoshiji Amagai 		de1 = (struct nilfs_dir_entry *)((char *)de + name_len);
5276cda9fa2SRyusuke Konishi 		de1->rec_len = nilfs_rec_len_to_disk(rec_len - name_len);
5286cda9fa2SRyusuke Konishi 		de->rec_len = nilfs_rec_len_to_disk(name_len);
5292ba466d7SYoshiji Amagai 		de = de1;
5302ba466d7SYoshiji Amagai 	}
5312ba466d7SYoshiji Amagai 	de->name_len = namelen;
5322ba466d7SYoshiji Amagai 	memcpy(de->name, name, namelen);
5332ba466d7SYoshiji Amagai 	de->inode = cpu_to_le64(inode->i_ino);
5342ba466d7SYoshiji Amagai 	nilfs_set_de_type(de, inode);
5359bff5f98SMatthew Wilcox (Oracle) 	nilfs_commit_chunk(folio, folio->mapping, from, to);
536b3e1cc39SJeff Layton 	inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
537abdb318bSJiro SEKIBA 	nilfs_mark_inode_dirty(dir);
5382ba466d7SYoshiji Amagai 	/* OFFSET_CACHE */
5392ba466d7SYoshiji Amagai out_put:
540f59bb60fSMatthew Wilcox (Oracle) 	folio_release_kmap(folio, de);
5412ba466d7SYoshiji Amagai 	return err;
5422ba466d7SYoshiji Amagai out_unlock:
543f59bb60fSMatthew Wilcox (Oracle) 	folio_unlock(folio);
5442ba466d7SYoshiji Amagai 	goto out_put;
5452ba466d7SYoshiji Amagai }
5462ba466d7SYoshiji Amagai 
5472ba466d7SYoshiji Amagai /*
5482ba466d7SYoshiji Amagai  * nilfs_delete_entry deletes a directory entry by merging it with the
5496f133c97SMatthew Wilcox (Oracle)  * previous entry. Folio is up-to-date.
5502ba466d7SYoshiji Amagai  */
5516f133c97SMatthew Wilcox (Oracle) int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct folio *folio)
5522ba466d7SYoshiji Amagai {
5536f133c97SMatthew Wilcox (Oracle) 	struct address_space *mapping = folio->mapping;
5542ba466d7SYoshiji Amagai 	struct inode *inode = mapping->host;
5556f133c97SMatthew Wilcox (Oracle) 	char *kaddr = (char *)((unsigned long)dir & ~(folio_size(folio) - 1));
5566f133c97SMatthew Wilcox (Oracle) 	size_t from, to;
5570c6c44cbSRyusuke Konishi 	struct nilfs_dir_entry *de, *pde = NULL;
5582ba466d7SYoshiji Amagai 	int err;
5592ba466d7SYoshiji Amagai 
5600c6c44cbSRyusuke Konishi 	from = ((char *)dir - kaddr) & ~(nilfs_chunk_size(inode) - 1);
5610c6c44cbSRyusuke Konishi 	to = ((char *)dir - kaddr) + nilfs_rec_len_from_disk(dir->rec_len);
5620c6c44cbSRyusuke Konishi 	de = (struct nilfs_dir_entry *)(kaddr + from);
5630c6c44cbSRyusuke Konishi 
5642ba466d7SYoshiji Amagai 	while ((char *)de < (char *)dir) {
5652ba466d7SYoshiji Amagai 		if (de->rec_len == 0) {
566cae3d4caSRyusuke Konishi 			nilfs_error(inode->i_sb,
5672ba466d7SYoshiji Amagai 				    "zero-length directory entry");
5682ba466d7SYoshiji Amagai 			err = -EIO;
5692ba466d7SYoshiji Amagai 			goto out;
5702ba466d7SYoshiji Amagai 		}
5712ba466d7SYoshiji Amagai 		pde = de;
5722ba466d7SYoshiji Amagai 		de = nilfs_next_entry(de);
5732ba466d7SYoshiji Amagai 	}
5742ba466d7SYoshiji Amagai 	if (pde)
5756af2191fSMatthew Wilcox (Oracle) 		from = (char *)pde - kaddr;
5766f133c97SMatthew Wilcox (Oracle) 	folio_lock(folio);
5779bff5f98SMatthew Wilcox (Oracle) 	err = nilfs_prepare_chunk(folio, from, to);
5782ba466d7SYoshiji Amagai 	BUG_ON(err);
5792ba466d7SYoshiji Amagai 	if (pde)
5806cda9fa2SRyusuke Konishi 		pde->rec_len = nilfs_rec_len_to_disk(to - from);
5812ba466d7SYoshiji Amagai 	dir->inode = 0;
5829bff5f98SMatthew Wilcox (Oracle) 	nilfs_commit_chunk(folio, mapping, from, to);
583b3e1cc39SJeff Layton 	inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
5842ba466d7SYoshiji Amagai out:
5852ba466d7SYoshiji Amagai 	return err;
5862ba466d7SYoshiji Amagai }
5872ba466d7SYoshiji Amagai 
5882ba466d7SYoshiji Amagai /*
5892ba466d7SYoshiji Amagai  * Set the first fragment of directory.
5902ba466d7SYoshiji Amagai  */
5912ba466d7SYoshiji Amagai int nilfs_make_empty(struct inode *inode, struct inode *parent)
5922ba466d7SYoshiji Amagai {
5932ba466d7SYoshiji Amagai 	struct address_space *mapping = inode->i_mapping;
5940743230fSMatthew Wilcox (Oracle) 	struct folio *folio = filemap_grab_folio(mapping, 0);
5950c6c44cbSRyusuke Konishi 	unsigned int chunk_size = nilfs_chunk_size(inode);
5962ba466d7SYoshiji Amagai 	struct nilfs_dir_entry *de;
5972ba466d7SYoshiji Amagai 	int err;
5982ba466d7SYoshiji Amagai 	void *kaddr;
5992ba466d7SYoshiji Amagai 
6000743230fSMatthew Wilcox (Oracle) 	if (IS_ERR(folio))
6010743230fSMatthew Wilcox (Oracle) 		return PTR_ERR(folio);
6022ba466d7SYoshiji Amagai 
6039bff5f98SMatthew Wilcox (Oracle) 	err = nilfs_prepare_chunk(folio, 0, chunk_size);
6042ba466d7SYoshiji Amagai 	if (unlikely(err)) {
6050743230fSMatthew Wilcox (Oracle) 		folio_unlock(folio);
6062ba466d7SYoshiji Amagai 		goto fail;
6072ba466d7SYoshiji Amagai 	}
6080743230fSMatthew Wilcox (Oracle) 	kaddr = kmap_local_folio(folio, 0);
6092ba466d7SYoshiji Amagai 	memset(kaddr, 0, chunk_size);
6102ba466d7SYoshiji Amagai 	de = (struct nilfs_dir_entry *)kaddr;
6112ba466d7SYoshiji Amagai 	de->name_len = 1;
6126cda9fa2SRyusuke Konishi 	de->rec_len = nilfs_rec_len_to_disk(NILFS_DIR_REC_LEN(1));
6132ba466d7SYoshiji Amagai 	memcpy(de->name, ".\0\0", 4);
6142ba466d7SYoshiji Amagai 	de->inode = cpu_to_le64(inode->i_ino);
6152ba466d7SYoshiji Amagai 	nilfs_set_de_type(de, inode);
6162ba466d7SYoshiji Amagai 
6172ba466d7SYoshiji Amagai 	de = (struct nilfs_dir_entry *)(kaddr + NILFS_DIR_REC_LEN(1));
6182ba466d7SYoshiji Amagai 	de->name_len = 2;
6196cda9fa2SRyusuke Konishi 	de->rec_len = nilfs_rec_len_to_disk(chunk_size - NILFS_DIR_REC_LEN(1));
6202ba466d7SYoshiji Amagai 	de->inode = cpu_to_le64(parent->i_ino);
6212ba466d7SYoshiji Amagai 	memcpy(de->name, "..\0", 4);
6222ba466d7SYoshiji Amagai 	nilfs_set_de_type(de, inode);
6230743230fSMatthew Wilcox (Oracle) 	kunmap_local(kaddr);
6249bff5f98SMatthew Wilcox (Oracle) 	nilfs_commit_chunk(folio, mapping, 0, chunk_size);
6252ba466d7SYoshiji Amagai fail:
6260743230fSMatthew Wilcox (Oracle) 	folio_put(folio);
6272ba466d7SYoshiji Amagai 	return err;
6282ba466d7SYoshiji Amagai }
6292ba466d7SYoshiji Amagai 
6302ba466d7SYoshiji Amagai /*
6312ba466d7SYoshiji Amagai  * routine to check that the specified directory is empty (for rmdir)
6322ba466d7SYoshiji Amagai  */
6332ba466d7SYoshiji Amagai int nilfs_empty_dir(struct inode *inode)
6342ba466d7SYoshiji Amagai {
63518f03ddfSMatthew Wilcox (Oracle) 	struct folio *folio = NULL;
6369b77f66fSMatthew Wilcox (Oracle) 	char *kaddr;
6372ba466d7SYoshiji Amagai 	unsigned long i, npages = dir_pages(inode);
6382ba466d7SYoshiji Amagai 
6392ba466d7SYoshiji Amagai 	for (i = 0; i < npages; i++) {
6402ba466d7SYoshiji Amagai 		struct nilfs_dir_entry *de;
6412ba466d7SYoshiji Amagai 
64218f03ddfSMatthew Wilcox (Oracle) 		kaddr = nilfs_get_folio(inode, i, &folio);
64309a46acbSMatthew Wilcox (Oracle) 		if (IS_ERR(kaddr))
6447373a51eSRyusuke Konishi 			return 0;
6452ba466d7SYoshiji Amagai 
6462ba466d7SYoshiji Amagai 		de = (struct nilfs_dir_entry *)kaddr;
6472ba466d7SYoshiji Amagai 		kaddr += nilfs_last_byte(inode, i) - NILFS_DIR_REC_LEN(1);
6482ba466d7SYoshiji Amagai 
6492ba466d7SYoshiji Amagai 		while ((char *)de <= kaddr) {
6502ba466d7SYoshiji Amagai 			if (de->rec_len == 0) {
651cae3d4caSRyusuke Konishi 				nilfs_error(inode->i_sb,
65206f4abf6SRyusuke Konishi 					    "zero-length directory entry (kaddr=%p, de=%p)",
65306f4abf6SRyusuke Konishi 					    kaddr, de);
6542ba466d7SYoshiji Amagai 				goto not_empty;
6552ba466d7SYoshiji Amagai 			}
6562ba466d7SYoshiji Amagai 			if (de->inode != 0) {
6572ba466d7SYoshiji Amagai 				/* check for . and .. */
6582ba466d7SYoshiji Amagai 				if (de->name[0] != '.')
6592ba466d7SYoshiji Amagai 					goto not_empty;
6602ba466d7SYoshiji Amagai 				if (de->name_len > 2)
6612ba466d7SYoshiji Amagai 					goto not_empty;
6622ba466d7SYoshiji Amagai 				if (de->name_len < 2) {
6632ba466d7SYoshiji Amagai 					if (de->inode !=
6642ba466d7SYoshiji Amagai 					    cpu_to_le64(inode->i_ino))
6652ba466d7SYoshiji Amagai 						goto not_empty;
6662ba466d7SYoshiji Amagai 				} else if (de->name[1] != '.')
6672ba466d7SYoshiji Amagai 					goto not_empty;
6682ba466d7SYoshiji Amagai 			}
6692ba466d7SYoshiji Amagai 			de = nilfs_next_entry(de);
6702ba466d7SYoshiji Amagai 		}
67118f03ddfSMatthew Wilcox (Oracle) 		folio_release_kmap(folio, kaddr);
6722ba466d7SYoshiji Amagai 	}
6732ba466d7SYoshiji Amagai 	return 1;
6742ba466d7SYoshiji Amagai 
6752ba466d7SYoshiji Amagai not_empty:
67618f03ddfSMatthew Wilcox (Oracle) 	folio_release_kmap(folio, kaddr);
6772ba466d7SYoshiji Amagai 	return 0;
6782ba466d7SYoshiji Amagai }
6792ba466d7SYoshiji Amagai 
680828c0950SAlexey Dobriyan const struct file_operations nilfs_dir_operations = {
6812ba466d7SYoshiji Amagai 	.llseek		= generic_file_llseek,
6822ba466d7SYoshiji Amagai 	.read		= generic_read_dir,
683c51da20cSAl Viro 	.iterate_shared	= nilfs_readdir,
6847a946193SRyusuke Konishi 	.unlocked_ioctl	= nilfs_ioctl,
6852ba466d7SYoshiji Amagai #ifdef CONFIG_COMPAT
686828b1c50SRyusuke Konishi 	.compat_ioctl	= nilfs_compat_ioctl,
6872ba466d7SYoshiji Amagai #endif	/* CONFIG_COMPAT */
6882ba466d7SYoshiji Amagai 	.fsync		= nilfs_sync_file,
6892ba466d7SYoshiji Amagai 
6902ba466d7SYoshiji Amagai };
691