brintos

brintos / linux-shallow public Read only

0
0
Text · 16.3 KiB · d6e6a21 Raw
658 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  linux/fs/ufs/ufs_dir.c4 *5 * Copyright (C) 19966 * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)7 * Laboratory for Computer Science Research Computing Facility8 * Rutgers, The State University of New Jersey9 *10 * swab support by Francois-Rene Rideau <fare@tunes.org> 1997040611 *12 * 4.4BSD (FreeBSD) support added on February 1st 1998 by13 * Niels Kristian Bech Jensen <nkbj@image.dk> partially based14 * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.15 *16 * Migration to usage of "page cache" on May 2006 by17 * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.18 */19 20#include <linux/time.h>21#include <linux/fs.h>22#include <linux/swap.h>23#include <linux/iversion.h>24 25#include "ufs_fs.h"26#include "ufs.h"27#include "swab.h"28#include "util.h"29 30/*31 * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.32 *33 * len <= UFS_MAXNAMLEN and de != NULL are guaranteed by caller.34 */35static inline int ufs_match(struct super_block *sb, int len,36		const unsigned char *name, struct ufs_dir_entry *de)37{38	if (len != ufs_get_de_namlen(sb, de))39		return 0;40	if (!de->d_ino)41		return 0;42	return !memcmp(name, de->d_name, len);43}44 45static void ufs_commit_chunk(struct folio *folio, loff_t pos, unsigned len)46{47	struct address_space *mapping = folio->mapping;48	struct inode *dir = mapping->host;49 50	inode_inc_iversion(dir);51	block_write_end(NULL, mapping, pos, len, len, folio, NULL);52	if (pos+len > dir->i_size) {53		i_size_write(dir, pos+len);54		mark_inode_dirty(dir);55	}56	folio_unlock(folio);57}58 59static int ufs_handle_dirsync(struct inode *dir)60{61	int err;62 63	err = filemap_write_and_wait(dir->i_mapping);64	if (!err)65		err = sync_inode_metadata(dir, 1);66	return err;67}68 69ino_t ufs_inode_by_name(struct inode *dir, const struct qstr *qstr)70{71	ino_t res = 0;72	struct ufs_dir_entry *de;73	struct folio *folio;74	75	de = ufs_find_entry(dir, qstr, &folio);76	if (de) {77		res = fs32_to_cpu(dir->i_sb, de->d_ino);78		folio_release_kmap(folio, de);79	}80	return res;81}82 83 84/* Releases the page */85void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,86		  struct folio *folio, struct inode *inode,87		  bool update_times)88{89	loff_t pos = folio_pos(folio) + offset_in_folio(folio, de);90	unsigned len = fs16_to_cpu(dir->i_sb, de->d_reclen);91	int err;92 93	folio_lock(folio);94	err = ufs_prepare_chunk(folio, pos, len);95	BUG_ON(err);96 97	de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);98	ufs_set_de_type(dir->i_sb, de, inode->i_mode);99 100	ufs_commit_chunk(folio, pos, len);101	folio_release_kmap(folio, de);102	if (update_times)103		inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));104	mark_inode_dirty(dir);105	ufs_handle_dirsync(dir);106}107 108static bool ufs_check_folio(struct folio *folio, char *kaddr)109{110	struct inode *dir = folio->mapping->host;111	struct super_block *sb = dir->i_sb;112	unsigned offs, rec_len;113	unsigned limit = folio_size(folio);114	const unsigned chunk_mask = UFS_SB(sb)->s_uspi->s_dirblksize - 1;115	struct ufs_dir_entry *p;116	char *error;117 118	if (dir->i_size < folio_pos(folio) + limit) {119		limit = offset_in_folio(folio, dir->i_size);120		if (limit & chunk_mask)121			goto Ebadsize;122		if (!limit)123			goto out;124	}125	for (offs = 0; offs <= limit - UFS_DIR_REC_LEN(1); offs += rec_len) {126		p = (struct ufs_dir_entry *)(kaddr + offs);127		rec_len = fs16_to_cpu(sb, p->d_reclen);128 129		if (rec_len < UFS_DIR_REC_LEN(1))130			goto Eshort;131		if (rec_len & 3)132			goto Ealign;133		if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p)))134			goto Enamelen;135		if (((offs + rec_len - 1) ^ offs) & ~chunk_mask)136			goto Espan;137		if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *138						  UFS_SB(sb)->s_uspi->s_ncg))139			goto Einumber;140	}141	if (offs != limit)142		goto Eend;143out:144	folio_set_checked(folio);145	return true;146 147	/* Too bad, we had an error */148 149Ebadsize:150	ufs_error(sb, __func__,151		  "size of directory #%lu is not a multiple of chunk size",152		  dir->i_ino153	);154	goto fail;155Eshort:156	error = "rec_len is smaller than minimal";157	goto bad_entry;158Ealign:159	error = "unaligned directory entry";160	goto bad_entry;161Enamelen:162	error = "rec_len is too small for name_len";163	goto bad_entry;164Espan:165	error = "directory entry across blocks";166	goto bad_entry;167Einumber:168	error = "inode out of bounds";169bad_entry:170	ufs_error(sb, __func__, "bad entry in directory #%lu: %s - "171		   "offset=%llu, rec_len=%d, name_len=%d",172		   dir->i_ino, error, folio_pos(folio) + offs,173		   rec_len, ufs_get_de_namlen(sb, p));174	goto fail;175Eend:176	p = (struct ufs_dir_entry *)(kaddr + offs);177	ufs_error(sb, __func__,178		   "entry in directory #%lu spans the page boundary"179		   "offset=%llu",180		   dir->i_ino, folio_pos(folio) + offs);181fail:182	return false;183}184 185static void *ufs_get_folio(struct inode *dir, unsigned long n,186		struct folio **foliop)187{188	struct address_space *mapping = dir->i_mapping;189	struct folio *folio = read_mapping_folio(mapping, n, NULL);190	void *kaddr;191 192	if (IS_ERR(folio))193		return ERR_CAST(folio);194	kaddr = kmap_local_folio(folio, 0);195	if (unlikely(!folio_test_checked(folio))) {196		if (!ufs_check_folio(folio, kaddr))197			goto fail;198	}199	*foliop = folio;200	return kaddr;201 202fail:203	folio_release_kmap(folio, kaddr);204	return ERR_PTR(-EIO);205}206 207/*208 * Return the offset into page `page_nr' of the last valid209 * byte in that page, plus one.210 */211static unsigned212ufs_last_byte(struct inode *inode, unsigned long page_nr)213{214	unsigned last_byte = inode->i_size;215 216	last_byte -= page_nr << PAGE_SHIFT;217	if (last_byte > PAGE_SIZE)218		last_byte = PAGE_SIZE;219	return last_byte;220}221 222static inline struct ufs_dir_entry *223ufs_next_entry(struct super_block *sb, struct ufs_dir_entry *p)224{225	return (struct ufs_dir_entry *)((char *)p +226					fs16_to_cpu(sb, p->d_reclen));227}228 229struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct folio **foliop)230{231	struct ufs_dir_entry *de = ufs_get_folio(dir, 0, foliop);232 233	if (!IS_ERR(de))234		return ufs_next_entry(dir->i_sb, de);235 236	return NULL;237}238 239/*240 *	ufs_find_entry()241 *242 * finds an entry in the specified directory with the wanted name. It243 * returns the page in which the entry was found, and the entry itself244 * (as a parameter - res_dir). Page is returned mapped and unlocked.245 * Entry is guaranteed to be valid.246 */247struct ufs_dir_entry *ufs_find_entry(struct inode *dir, const struct qstr *qstr,248				     struct folio **foliop)249{250	struct super_block *sb = dir->i_sb;251	const unsigned char *name = qstr->name;252	int namelen = qstr->len;253	unsigned reclen = UFS_DIR_REC_LEN(namelen);254	unsigned long start, n;255	unsigned long npages = dir_pages(dir);256	struct ufs_inode_info *ui = UFS_I(dir);257	struct ufs_dir_entry *de;258 259	UFSD("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen);260 261	if (npages == 0 || namelen > UFS_MAXNAMLEN)262		goto out;263 264	start = ui->i_dir_start_lookup;265 266	if (start >= npages)267		start = 0;268	n = start;269	do {270		char *kaddr = ufs_get_folio(dir, n, foliop);271 272		if (!IS_ERR(kaddr)) {273			de = (struct ufs_dir_entry *)kaddr;274			kaddr += ufs_last_byte(dir, n) - reclen;275			while ((char *) de <= kaddr) {276				if (ufs_match(sb, namelen, name, de))277					goto found;278				de = ufs_next_entry(sb, de);279			}280			folio_release_kmap(*foliop, kaddr);281		}282		if (++n >= npages)283			n = 0;284	} while (n != start);285out:286	return NULL;287 288found:289	ui->i_dir_start_lookup = n;290	return de;291}292 293/*294 *	Parent is locked.295 */296int ufs_add_link(struct dentry *dentry, struct inode *inode)297{298	struct inode *dir = d_inode(dentry->d_parent);299	const unsigned char *name = dentry->d_name.name;300	int namelen = dentry->d_name.len;301	struct super_block *sb = dir->i_sb;302	unsigned reclen = UFS_DIR_REC_LEN(namelen);303	const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize;304	unsigned short rec_len, name_len;305	struct folio *folio = NULL;306	struct ufs_dir_entry *de;307	unsigned long npages = dir_pages(dir);308	unsigned long n;309	loff_t pos;310	int err;311 312	UFSD("ENTER, name %s, namelen %u\n", name, namelen);313 314	/*315	 * We take care of directory expansion in the same loop.316	 * This code plays outside i_size, so it locks the folio317	 * to protect that region.318	 */319	for (n = 0; n <= npages; n++) {320		char *kaddr = ufs_get_folio(dir, n, &folio);321		char *dir_end;322 323		if (IS_ERR(kaddr))324			return PTR_ERR(kaddr);325		folio_lock(folio);326		dir_end = kaddr + ufs_last_byte(dir, n);327		de = (struct ufs_dir_entry *)kaddr;328		kaddr += folio_size(folio) - reclen;329		while ((char *)de <= kaddr) {330			if ((char *)de == dir_end) {331				/* We hit i_size */332				name_len = 0;333				rec_len = chunk_size;334				de->d_reclen = cpu_to_fs16(sb, chunk_size);335				de->d_ino = 0;336				goto got_it;337			}338			if (de->d_reclen == 0) {339				ufs_error(dir->i_sb, __func__,340					  "zero-length directory entry");341				err = -EIO;342				goto out_unlock;343			}344			err = -EEXIST;345			if (ufs_match(sb, namelen, name, de))346				goto out_unlock;347			name_len = UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de));348			rec_len = fs16_to_cpu(sb, de->d_reclen);349			if (!de->d_ino && rec_len >= reclen)350				goto got_it;351			if (rec_len >= name_len + reclen)352				goto got_it;353			de = (struct ufs_dir_entry *) ((char *) de + rec_len);354		}355		folio_unlock(folio);356		folio_release_kmap(folio, kaddr);357	}358	BUG();359	return -EINVAL;360 361got_it:362	pos = folio_pos(folio) + offset_in_folio(folio, de);363	err = ufs_prepare_chunk(folio, pos, rec_len);364	if (err)365		goto out_unlock;366	if (de->d_ino) {367		struct ufs_dir_entry *de1 =368			(struct ufs_dir_entry *) ((char *) de + name_len);369		de1->d_reclen = cpu_to_fs16(sb, rec_len - name_len);370		de->d_reclen = cpu_to_fs16(sb, name_len);371 372		de = de1;373	}374 375	ufs_set_de_namlen(sb, de, namelen);376	memcpy(de->d_name, name, namelen + 1);377	de->d_ino = cpu_to_fs32(sb, inode->i_ino);378	ufs_set_de_type(sb, de, inode->i_mode);379 380	ufs_commit_chunk(folio, pos, rec_len);381	inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));382 383	mark_inode_dirty(dir);384	err = ufs_handle_dirsync(dir);385	/* OFFSET_CACHE */386out_put:387	folio_release_kmap(folio, de);388	return err;389out_unlock:390	folio_unlock(folio);391	goto out_put;392}393 394static inline unsigned395ufs_validate_entry(struct super_block *sb, char *base,396		   unsigned offset, unsigned mask)397{398	struct ufs_dir_entry *de = (struct ufs_dir_entry*)(base + offset);399	struct ufs_dir_entry *p = (struct ufs_dir_entry*)(base + (offset&mask));400	while ((char*)p < (char*)de)401		p = ufs_next_entry(sb, p);402	return (char *)p - base;403}404 405 406/*407 * This is blatantly stolen from ext2fs408 */409static int410ufs_readdir(struct file *file, struct dir_context *ctx)411{412	loff_t pos = ctx->pos;413	struct inode *inode = file_inode(file);414	struct super_block *sb = inode->i_sb;415	unsigned int offset = pos & ~PAGE_MASK;416	unsigned long n = pos >> PAGE_SHIFT;417	unsigned long npages = dir_pages(inode);418	unsigned chunk_mask = ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);419	bool need_revalidate = !inode_eq_iversion(inode, *(u64 *)file->private_data);420	unsigned flags = UFS_SB(sb)->s_flags;421 422	UFSD("BEGIN\n");423 424	if (pos > inode->i_size - UFS_DIR_REC_LEN(1))425		return 0;426 427	for ( ; n < npages; n++, offset = 0) {428		struct ufs_dir_entry *de;429		struct folio *folio;430		char *kaddr = ufs_get_folio(inode, n, &folio);431		char *limit;432 433		if (IS_ERR(kaddr)) {434			ufs_error(sb, __func__,435				  "bad page in #%lu",436				  inode->i_ino);437			ctx->pos += PAGE_SIZE - offset;438			return PTR_ERR(kaddr);439		}440		if (unlikely(need_revalidate)) {441			if (offset) {442				offset = ufs_validate_entry(sb, kaddr, offset, chunk_mask);443				ctx->pos = (n<<PAGE_SHIFT) + offset;444			}445			*(u64 *)file->private_data = inode_query_iversion(inode);446			need_revalidate = false;447		}448		de = (struct ufs_dir_entry *)(kaddr+offset);449		limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1);450		for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) {451			if (de->d_ino) {452				unsigned char d_type = DT_UNKNOWN;453 454				UFSD("filldir(%s,%u)\n", de->d_name,455				      fs32_to_cpu(sb, de->d_ino));456				UFSD("namlen %u\n", ufs_get_de_namlen(sb, de));457 458				if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)459					d_type = de->d_u.d_44.d_type;460 461				if (!dir_emit(ctx, de->d_name,462					       ufs_get_de_namlen(sb, de),463					       fs32_to_cpu(sb, de->d_ino),464					       d_type)) {465					folio_release_kmap(folio, de);466					return 0;467				}468			}469			ctx->pos += fs16_to_cpu(sb, de->d_reclen);470		}471		folio_release_kmap(folio, kaddr);472	}473	return 0;474}475 476 477/*478 * ufs_delete_entry deletes a directory entry by merging it with the479 * previous entry.480 */481int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,482		     struct folio *folio)483{484	struct super_block *sb = inode->i_sb;485	size_t from, to;486	char *kaddr;487	loff_t pos;488	struct ufs_dir_entry *de, *pde = NULL;489	int err;490 491	UFSD("ENTER\n");492 493	from = offset_in_folio(folio, dir);494	to = from + fs16_to_cpu(sb, dir->d_reclen);495	kaddr = (char *)dir - from;496	from &= ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);497	de = (struct ufs_dir_entry *) (kaddr + from);498 499	UFSD("ino %u, reclen %u, namlen %u, name %s\n",500	      fs32_to_cpu(sb, de->d_ino),501	      fs16_to_cpu(sb, de->d_reclen),502	      ufs_get_de_namlen(sb, de), de->d_name);503 504	while ((char*)de < (char*)dir) {505		if (de->d_reclen == 0) {506			ufs_error(inode->i_sb, __func__,507				  "zero-length directory entry");508			err = -EIO;509			goto out;510		}511		pde = de;512		de = ufs_next_entry(sb, de);513	}514	if (pde)515		from = offset_in_folio(folio, pde);516	pos = folio_pos(folio) + from;517	folio_lock(folio);518	err = ufs_prepare_chunk(folio, pos, to - from);519	BUG_ON(err);520	if (pde)521		pde->d_reclen = cpu_to_fs16(sb, to - from);522	dir->d_ino = 0;523	ufs_commit_chunk(folio, pos, to - from);524	inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));525	mark_inode_dirty(inode);526	err = ufs_handle_dirsync(inode);527out:528	folio_release_kmap(folio, kaddr);529	UFSD("EXIT\n");530	return err;531}532 533int ufs_make_empty(struct inode * inode, struct inode *dir)534{535	struct super_block * sb = dir->i_sb;536	struct address_space *mapping = inode->i_mapping;537	struct folio *folio = filemap_grab_folio(mapping, 0);538	const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize;539	struct ufs_dir_entry * de;540	int err;541	char *kaddr;542 543	if (IS_ERR(folio))544		return PTR_ERR(folio);545 546	err = ufs_prepare_chunk(folio, 0, chunk_size);547	if (err) {548		folio_unlock(folio);549		goto fail;550	}551 552	kaddr = kmap_local_folio(folio, 0);553	memset(kaddr, 0, folio_size(folio));554 555	de = (struct ufs_dir_entry *)kaddr;556 557	de->d_ino = cpu_to_fs32(sb, inode->i_ino);558	ufs_set_de_type(sb, de, inode->i_mode);559	ufs_set_de_namlen(sb, de, 1);560	de->d_reclen = cpu_to_fs16(sb, UFS_DIR_REC_LEN(1));561	strcpy (de->d_name, ".");562	de = (struct ufs_dir_entry *)563		((char *)de + fs16_to_cpu(sb, de->d_reclen));564	de->d_ino = cpu_to_fs32(sb, dir->i_ino);565	ufs_set_de_type(sb, de, dir->i_mode);566	de->d_reclen = cpu_to_fs16(sb, chunk_size - UFS_DIR_REC_LEN(1));567	ufs_set_de_namlen(sb, de, 2);568	strcpy (de->d_name, "..");569	kunmap_local(kaddr);570 571	ufs_commit_chunk(folio, 0, chunk_size);572	err = ufs_handle_dirsync(inode);573fail:574	folio_put(folio);575	return err;576}577 578/*579 * routine to check that the specified directory is empty (for rmdir)580 */581int ufs_empty_dir(struct inode * inode)582{583	struct super_block *sb = inode->i_sb;584	struct folio *folio;585	char *kaddr;586	unsigned long i, npages = dir_pages(inode);587 588	for (i = 0; i < npages; i++) {589		struct ufs_dir_entry *de;590 591		kaddr = ufs_get_folio(inode, i, &folio);592		if (IS_ERR(kaddr))593			continue;594 595		de = (struct ufs_dir_entry *)kaddr;596		kaddr += ufs_last_byte(inode, i) - UFS_DIR_REC_LEN(1);597 598		while ((char *)de <= kaddr) {599			if (de->d_reclen == 0) {600				ufs_error(inode->i_sb, __func__,601					"zero-length directory entry: "602					"kaddr=%p, de=%p\n", kaddr, de);603				goto not_empty;604			}605			if (de->d_ino) {606				u16 namelen=ufs_get_de_namlen(sb, de);607				/* check for . and .. */608				if (de->d_name[0] != '.')609					goto not_empty;610				if (namelen > 2)611					goto not_empty;612				if (namelen < 2) {613					if (inode->i_ino !=614					    fs32_to_cpu(sb, de->d_ino))615						goto not_empty;616				} else if (de->d_name[1] != '.')617					goto not_empty;618			}619			de = ufs_next_entry(sb, de);620		}621		folio_release_kmap(folio, kaddr);622	}623	return 1;624 625not_empty:626	folio_release_kmap(folio, kaddr);627	return 0;628}629 630static int ufs_dir_open(struct inode *inode, struct file *file)631{632	file->private_data = kzalloc(sizeof(u64), GFP_KERNEL);633	if (!file->private_data)634		return -ENOMEM;635	return 0;636}637 638static int ufs_dir_release(struct inode *inode, struct file *file)639{640	kfree(file->private_data);641	return 0;642}643 644static loff_t ufs_dir_llseek(struct file *file, loff_t offset, int whence)645{646	return generic_llseek_cookie(file, offset, whence,647				     (u64 *)file->private_data);648}649 650const struct file_operations ufs_dir_operations = {651	.open		= ufs_dir_open,652	.release	= ufs_dir_release,653	.read		= generic_read_dir,654	.iterate_shared	= ufs_readdir,655	.fsync		= generic_file_fsync,656	.llseek		= ufs_dir_llseek,657};658