brintos

brintos / linux-shallow public Read only

0
0
Text · 12.9 KiB · 9b10805 Raw
587 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * NILFS pathname lookup operations.4 *5 * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.6 *7 * Modified for NILFS by Amagai Yoshiji and Ryusuke Konishi.8 */9/*10 *  linux/fs/ext2/namei.c11 *12 * Copyright (C) 1992, 1993, 1994, 199513 * Remy Card (card@masi.ibp.fr)14 * Laboratoire MASI - Institut Blaise Pascal15 * Universite Pierre et Marie Curie (Paris VI)16 *17 *  from18 *19 *  linux/fs/minix/namei.c20 *21 *  Copyright (C) 1991, 1992  Linus Torvalds22 *23 *  Big-endian to little-endian byte-swapping/bitmaps by24 *        David S. Miller (davem@caip.rutgers.edu), 199525 */26 27#include <linux/pagemap.h>28#include "nilfs.h"29#include "export.h"30 31#define NILFS_FID_SIZE_NON_CONNECTABLE \32	(offsetof(struct nilfs_fid, parent_gen) / 4)33#define NILFS_FID_SIZE_CONNECTABLE	(sizeof(struct nilfs_fid) / 4)34 35static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode)36{37	int err = nilfs_add_link(dentry, inode);38 39	if (!err) {40		d_instantiate_new(dentry, inode);41		return 0;42	}43	inode_dec_link_count(inode);44	unlock_new_inode(inode);45	iput(inode);46	return err;47}48 49/*50 * Methods themselves.51 */52 53static struct dentry *54nilfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)55{56	struct inode *inode;57	ino_t ino;58	int res;59 60	if (dentry->d_name.len > NILFS_NAME_LEN)61		return ERR_PTR(-ENAMETOOLONG);62 63	res = nilfs_inode_by_name(dir, &dentry->d_name, &ino);64	if (res) {65		if (res != -ENOENT)66			return ERR_PTR(res);67		inode = NULL;68	} else {69		inode = nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino);70	}71 72	return d_splice_alias(inode, dentry);73}74 75/*76 * By the time this is called, we already have created77 * the directory cache entry for the new file, but it78 * is so far negative - it has no inode.79 *80 * If the create succeeds, we fill in the inode information81 * with d_instantiate().82 */83static int nilfs_create(struct mnt_idmap *idmap, struct inode *dir,84			struct dentry *dentry, umode_t mode, bool excl)85{86	struct inode *inode;87	struct nilfs_transaction_info ti;88	int err;89 90	err = nilfs_transaction_begin(dir->i_sb, &ti, 1);91	if (err)92		return err;93	inode = nilfs_new_inode(dir, mode);94	err = PTR_ERR(inode);95	if (!IS_ERR(inode)) {96		inode->i_op = &nilfs_file_inode_operations;97		inode->i_fop = &nilfs_file_operations;98		inode->i_mapping->a_ops = &nilfs_aops;99		nilfs_mark_inode_dirty(inode);100		err = nilfs_add_nondir(dentry, inode);101	}102	if (!err)103		err = nilfs_transaction_commit(dir->i_sb);104	else105		nilfs_transaction_abort(dir->i_sb);106 107	return err;108}109 110static int111nilfs_mknod(struct mnt_idmap *idmap, struct inode *dir,112	    struct dentry *dentry, umode_t mode, dev_t rdev)113{114	struct inode *inode;115	struct nilfs_transaction_info ti;116	int err;117 118	err = nilfs_transaction_begin(dir->i_sb, &ti, 1);119	if (err)120		return err;121	inode = nilfs_new_inode(dir, mode);122	err = PTR_ERR(inode);123	if (!IS_ERR(inode)) {124		init_special_inode(inode, inode->i_mode, rdev);125		nilfs_mark_inode_dirty(inode);126		err = nilfs_add_nondir(dentry, inode);127	}128	if (!err)129		err = nilfs_transaction_commit(dir->i_sb);130	else131		nilfs_transaction_abort(dir->i_sb);132 133	return err;134}135 136static int nilfs_symlink(struct mnt_idmap *idmap, struct inode *dir,137			 struct dentry *dentry, const char *symname)138{139	struct nilfs_transaction_info ti;140	struct super_block *sb = dir->i_sb;141	unsigned int l = strlen(symname) + 1;142	struct inode *inode;143	int err;144 145	if (l > sb->s_blocksize)146		return -ENAMETOOLONG;147 148	err = nilfs_transaction_begin(dir->i_sb, &ti, 1);149	if (err)150		return err;151 152	inode = nilfs_new_inode(dir, S_IFLNK | 0777);153	err = PTR_ERR(inode);154	if (IS_ERR(inode))155		goto out;156 157	/* slow symlink */158	inode->i_op = &nilfs_symlink_inode_operations;159	inode_nohighmem(inode);160	mapping_set_gfp_mask(inode->i_mapping,161			     mapping_gfp_constraint(inode->i_mapping,162						    ~__GFP_FS));163	inode->i_mapping->a_ops = &nilfs_aops;164	err = page_symlink(inode, symname, l);165	if (err)166		goto out_fail;167 168	/* mark_inode_dirty(inode); */169	/* page_symlink() do this */170 171	err = nilfs_add_nondir(dentry, inode);172out:173	if (!err)174		err = nilfs_transaction_commit(dir->i_sb);175	else176		nilfs_transaction_abort(dir->i_sb);177 178	return err;179 180out_fail:181	drop_nlink(inode);182	nilfs_mark_inode_dirty(inode);183	unlock_new_inode(inode);184	iput(inode);185	goto out;186}187 188static int nilfs_link(struct dentry *old_dentry, struct inode *dir,189		      struct dentry *dentry)190{191	struct inode *inode = d_inode(old_dentry);192	struct nilfs_transaction_info ti;193	int err;194 195	err = nilfs_transaction_begin(dir->i_sb, &ti, 1);196	if (err)197		return err;198 199	inode_set_ctime_current(inode);200	inode_inc_link_count(inode);201	ihold(inode);202 203	err = nilfs_add_link(dentry, inode);204	if (!err) {205		d_instantiate(dentry, inode);206		err = nilfs_transaction_commit(dir->i_sb);207	} else {208		inode_dec_link_count(inode);209		iput(inode);210		nilfs_transaction_abort(dir->i_sb);211	}212 213	return err;214}215 216static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,217		       struct dentry *dentry, umode_t mode)218{219	struct inode *inode;220	struct nilfs_transaction_info ti;221	int err;222 223	err = nilfs_transaction_begin(dir->i_sb, &ti, 1);224	if (err)225		return err;226 227	inc_nlink(dir);228 229	inode = nilfs_new_inode(dir, S_IFDIR | mode);230	err = PTR_ERR(inode);231	if (IS_ERR(inode))232		goto out_dir;233 234	inode->i_op = &nilfs_dir_inode_operations;235	inode->i_fop = &nilfs_dir_operations;236	inode->i_mapping->a_ops = &nilfs_aops;237 238	inc_nlink(inode);239 240	err = nilfs_make_empty(inode, dir);241	if (err)242		goto out_fail;243 244	err = nilfs_add_link(dentry, inode);245	if (err)246		goto out_fail;247 248	nilfs_mark_inode_dirty(inode);249	d_instantiate_new(dentry, inode);250out:251	if (!err)252		err = nilfs_transaction_commit(dir->i_sb);253	else254		nilfs_transaction_abort(dir->i_sb);255 256	return err;257 258out_fail:259	drop_nlink(inode);260	drop_nlink(inode);261	nilfs_mark_inode_dirty(inode);262	unlock_new_inode(inode);263	iput(inode);264out_dir:265	drop_nlink(dir);266	nilfs_mark_inode_dirty(dir);267	goto out;268}269 270static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry)271{272	struct inode *inode;273	struct nilfs_dir_entry *de;274	struct folio *folio;275	int err;276 277	de = nilfs_find_entry(dir, &dentry->d_name, &folio);278	if (IS_ERR(de)) {279		err = PTR_ERR(de);280		goto out;281	}282 283	inode = d_inode(dentry);284	err = -EIO;285	if (le64_to_cpu(de->inode) != inode->i_ino)286		goto out;287 288	if (!inode->i_nlink) {289		nilfs_warn(inode->i_sb,290			   "deleting nonexistent file (ino=%lu), %d",291			   inode->i_ino, inode->i_nlink);292		set_nlink(inode, 1);293	}294	err = nilfs_delete_entry(de, folio);295	folio_release_kmap(folio, de);296	if (err)297		goto out;298 299	inode_set_ctime_to_ts(inode, inode_get_ctime(dir));300	drop_nlink(inode);301	err = 0;302out:303	return err;304}305 306static int nilfs_unlink(struct inode *dir, struct dentry *dentry)307{308	struct nilfs_transaction_info ti;309	int err;310 311	err = nilfs_transaction_begin(dir->i_sb, &ti, 0);312	if (err)313		return err;314 315	err = nilfs_do_unlink(dir, dentry);316 317	if (!err) {318		nilfs_mark_inode_dirty(dir);319		nilfs_mark_inode_dirty(d_inode(dentry));320		err = nilfs_transaction_commit(dir->i_sb);321	} else322		nilfs_transaction_abort(dir->i_sb);323 324	return err;325}326 327static int nilfs_rmdir(struct inode *dir, struct dentry *dentry)328{329	struct inode *inode = d_inode(dentry);330	struct nilfs_transaction_info ti;331	int err;332 333	err = nilfs_transaction_begin(dir->i_sb, &ti, 0);334	if (err)335		return err;336 337	err = -ENOTEMPTY;338	if (nilfs_empty_dir(inode)) {339		err = nilfs_do_unlink(dir, dentry);340		if (!err) {341			inode->i_size = 0;342			drop_nlink(inode);343			nilfs_mark_inode_dirty(inode);344			drop_nlink(dir);345			nilfs_mark_inode_dirty(dir);346		}347	}348	if (!err)349		err = nilfs_transaction_commit(dir->i_sb);350	else351		nilfs_transaction_abort(dir->i_sb);352 353	return err;354}355 356static int nilfs_rename(struct mnt_idmap *idmap,357			struct inode *old_dir, struct dentry *old_dentry,358			struct inode *new_dir, struct dentry *new_dentry,359			unsigned int flags)360{361	struct inode *old_inode = d_inode(old_dentry);362	struct inode *new_inode = d_inode(new_dentry);363	struct folio *dir_folio = NULL;364	struct nilfs_dir_entry *dir_de = NULL;365	struct folio *old_folio;366	struct nilfs_dir_entry *old_de;367	struct nilfs_transaction_info ti;368	int err;369 370	if (flags & ~RENAME_NOREPLACE)371		return -EINVAL;372 373	err = nilfs_transaction_begin(old_dir->i_sb, &ti, 1);374	if (unlikely(err))375		return err;376 377	old_de = nilfs_find_entry(old_dir, &old_dentry->d_name, &old_folio);378	if (IS_ERR(old_de)) {379		err = PTR_ERR(old_de);380		goto out;381	}382 383	if (S_ISDIR(old_inode->i_mode)) {384		err = -EIO;385		dir_de = nilfs_dotdot(old_inode, &dir_folio);386		if (!dir_de)387			goto out_old;388	}389 390	if (new_inode) {391		struct folio *new_folio;392		struct nilfs_dir_entry *new_de;393 394		err = -ENOTEMPTY;395		if (dir_de && !nilfs_empty_dir(new_inode))396			goto out_dir;397 398		new_de = nilfs_find_entry(new_dir, &new_dentry->d_name,399					  &new_folio);400		if (IS_ERR(new_de)) {401			err = PTR_ERR(new_de);402			goto out_dir;403		}404		nilfs_set_link(new_dir, new_de, new_folio, old_inode);405		folio_release_kmap(new_folio, new_de);406		nilfs_mark_inode_dirty(new_dir);407		inode_set_ctime_current(new_inode);408		if (dir_de)409			drop_nlink(new_inode);410		drop_nlink(new_inode);411		nilfs_mark_inode_dirty(new_inode);412	} else {413		err = nilfs_add_link(new_dentry, old_inode);414		if (err)415			goto out_dir;416		if (dir_de) {417			inc_nlink(new_dir);418			nilfs_mark_inode_dirty(new_dir);419		}420	}421 422	/*423	 * Like most other Unix systems, set the ctime for inodes on a424	 * rename.425	 */426	inode_set_ctime_current(old_inode);427 428	nilfs_delete_entry(old_de, old_folio);429 430	if (dir_de) {431		nilfs_set_link(old_inode, dir_de, dir_folio, new_dir);432		folio_release_kmap(dir_folio, dir_de);433		drop_nlink(old_dir);434	}435	folio_release_kmap(old_folio, old_de);436 437	nilfs_mark_inode_dirty(old_dir);438	nilfs_mark_inode_dirty(old_inode);439 440	err = nilfs_transaction_commit(old_dir->i_sb);441	return err;442 443out_dir:444	if (dir_de)445		folio_release_kmap(dir_folio, dir_de);446out_old:447	folio_release_kmap(old_folio, old_de);448out:449	nilfs_transaction_abort(old_dir->i_sb);450	return err;451}452 453/*454 * Export operations455 */456static struct dentry *nilfs_get_parent(struct dentry *child)457{458	ino_t ino;459	int res;460	struct nilfs_root *root;461 462	res = nilfs_inode_by_name(d_inode(child), &dotdot_name, &ino);463	if (res)464		return ERR_PTR(res);465 466	root = NILFS_I(d_inode(child))->i_root;467 468	return d_obtain_alias(nilfs_iget(child->d_sb, root, ino));469}470 471static struct dentry *nilfs_get_dentry(struct super_block *sb, u64 cno,472				       u64 ino, u32 gen)473{474	struct nilfs_root *root;475	struct inode *inode;476 477	if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO)478		return ERR_PTR(-ESTALE);479 480	root = nilfs_lookup_root(sb->s_fs_info, cno);481	if (!root)482		return ERR_PTR(-ESTALE);483 484	inode = nilfs_iget(sb, root, ino);485	nilfs_put_root(root);486 487	if (IS_ERR(inode))488		return ERR_CAST(inode);489	if (gen && inode->i_generation != gen) {490		iput(inode);491		return ERR_PTR(-ESTALE);492	}493	return d_obtain_alias(inode);494}495 496static struct dentry *nilfs_fh_to_dentry(struct super_block *sb, struct fid *fh,497					 int fh_len, int fh_type)498{499	struct nilfs_fid *fid = (struct nilfs_fid *)fh;500 501	if (fh_len < NILFS_FID_SIZE_NON_CONNECTABLE ||502	    (fh_type != FILEID_NILFS_WITH_PARENT &&503	     fh_type != FILEID_NILFS_WITHOUT_PARENT))504		return NULL;505 506	return nilfs_get_dentry(sb, fid->cno, fid->ino, fid->gen);507}508 509static struct dentry *nilfs_fh_to_parent(struct super_block *sb, struct fid *fh,510					 int fh_len, int fh_type)511{512	struct nilfs_fid *fid = (struct nilfs_fid *)fh;513 514	if (fh_len < NILFS_FID_SIZE_CONNECTABLE ||515	    fh_type != FILEID_NILFS_WITH_PARENT)516		return NULL;517 518	return nilfs_get_dentry(sb, fid->cno, fid->parent_ino, fid->parent_gen);519}520 521static int nilfs_encode_fh(struct inode *inode, __u32 *fh, int *lenp,522			   struct inode *parent)523{524	struct nilfs_fid *fid = (struct nilfs_fid *)fh;525	struct nilfs_root *root = NILFS_I(inode)->i_root;526	int type;527 528	if (parent && *lenp < NILFS_FID_SIZE_CONNECTABLE) {529		*lenp = NILFS_FID_SIZE_CONNECTABLE;530		return FILEID_INVALID;531	}532	if (*lenp < NILFS_FID_SIZE_NON_CONNECTABLE) {533		*lenp = NILFS_FID_SIZE_NON_CONNECTABLE;534		return FILEID_INVALID;535	}536 537	fid->cno = root->cno;538	fid->ino = inode->i_ino;539	fid->gen = inode->i_generation;540 541	if (parent) {542		fid->parent_ino = parent->i_ino;543		fid->parent_gen = parent->i_generation;544		type = FILEID_NILFS_WITH_PARENT;545		*lenp = NILFS_FID_SIZE_CONNECTABLE;546	} else {547		type = FILEID_NILFS_WITHOUT_PARENT;548		*lenp = NILFS_FID_SIZE_NON_CONNECTABLE;549	}550 551	return type;552}553 554const struct inode_operations nilfs_dir_inode_operations = {555	.create		= nilfs_create,556	.lookup		= nilfs_lookup,557	.link		= nilfs_link,558	.unlink		= nilfs_unlink,559	.symlink	= nilfs_symlink,560	.mkdir		= nilfs_mkdir,561	.rmdir		= nilfs_rmdir,562	.mknod		= nilfs_mknod,563	.rename		= nilfs_rename,564	.setattr	= nilfs_setattr,565	.permission	= nilfs_permission,566	.fiemap		= nilfs_fiemap,567	.fileattr_get	= nilfs_fileattr_get,568	.fileattr_set	= nilfs_fileattr_set,569};570 571const struct inode_operations nilfs_special_inode_operations = {572	.setattr	= nilfs_setattr,573	.permission	= nilfs_permission,574};575 576const struct inode_operations nilfs_symlink_inode_operations = {577	.get_link	= page_get_link,578	.permission     = nilfs_permission,579};580 581const struct export_operations nilfs_export_ops = {582	.encode_fh = nilfs_encode_fh,583	.fh_to_dentry = nilfs_fh_to_dentry,584	.fh_to_parent = nilfs_fh_to_parent,585	.get_parent = nilfs_get_parent,586};587