cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

namei.c (11900B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * (C) 2001 Clemson University and The University of Chicago
      4 *
      5 * See COPYING in top-level directory.
      6 */
      7
      8/*
      9 *  Linux VFS namei operations.
     10 */
     11
     12#include "protocol.h"
     13#include "orangefs-kernel.h"
     14
     15/*
     16 * Get a newly allocated inode to go with a negative dentry.
     17 */
     18static int orangefs_create(struct user_namespace *mnt_userns,
     19			struct inode *dir,
     20			struct dentry *dentry,
     21			umode_t mode,
     22			bool exclusive)
     23{
     24	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
     25	struct orangefs_kernel_op_s *new_op;
     26	struct orangefs_object_kref ref;
     27	struct inode *inode;
     28	struct iattr iattr;
     29	int ret;
     30
     31	gossip_debug(GOSSIP_NAME_DEBUG, "%s: %pd\n",
     32		     __func__,
     33		     dentry);
     34
     35	new_op = op_alloc(ORANGEFS_VFS_OP_CREATE);
     36	if (!new_op)
     37		return -ENOMEM;
     38
     39	new_op->upcall.req.create.parent_refn = parent->refn;
     40
     41	fill_default_sys_attrs(new_op->upcall.req.create.attributes,
     42			       ORANGEFS_TYPE_METAFILE, mode);
     43
     44	strncpy(new_op->upcall.req.create.d_name,
     45		dentry->d_name.name, ORANGEFS_NAME_MAX - 1);
     46
     47	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
     48
     49	gossip_debug(GOSSIP_NAME_DEBUG,
     50		     "%s: %pd: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n",
     51		     __func__,
     52		     dentry,
     53		     &new_op->downcall.resp.create.refn.khandle,
     54		     new_op->downcall.resp.create.refn.fs_id,
     55		     new_op,
     56		     ret);
     57
     58	if (ret < 0)
     59		goto out;
     60
     61	ref = new_op->downcall.resp.create.refn;
     62
     63	inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0, &ref);
     64	if (IS_ERR(inode)) {
     65		gossip_err("%s: Failed to allocate inode for file :%pd:\n",
     66			   __func__,
     67			   dentry);
     68		ret = PTR_ERR(inode);
     69		goto out;
     70	}
     71
     72	gossip_debug(GOSSIP_NAME_DEBUG,
     73		     "%s: Assigned inode :%pU: for file :%pd:\n",
     74		     __func__,
     75		     get_khandle_from_ino(inode),
     76		     dentry);
     77
     78	d_instantiate_new(dentry, inode);
     79	orangefs_set_timeout(dentry);
     80
     81	gossip_debug(GOSSIP_NAME_DEBUG,
     82		     "%s: dentry instantiated for %pd\n",
     83		     __func__,
     84		     dentry);
     85
     86	memset(&iattr, 0, sizeof iattr);
     87	iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
     88	iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
     89	__orangefs_setattr(dir, &iattr);
     90	ret = 0;
     91out:
     92	op_release(new_op);
     93	gossip_debug(GOSSIP_NAME_DEBUG,
     94		     "%s: %pd: returning %d\n",
     95		     __func__,
     96		     dentry,
     97		     ret);
     98	return ret;
     99}
    100
    101/*
    102 * Attempt to resolve an object name (dentry->d_name), parent handle, and
    103 * fsid into a handle for the object.
    104 */
    105static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
    106				   unsigned int flags)
    107{
    108	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
    109	struct orangefs_kernel_op_s *new_op;
    110	struct inode *inode;
    111	int ret = -EINVAL;
    112
    113	/*
    114	 * in theory we could skip a lookup here (if the intent is to
    115	 * create) in order to avoid a potentially failed lookup, but
    116	 * leaving it in can skip a valid lookup and try to create a file
    117	 * that already exists (e.g. the vfs already handles checking for
    118	 * -EEXIST on O_EXCL opens, which is broken if we skip this lookup
    119	 * in the create path)
    120	 */
    121	gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %pd\n",
    122		     __func__, dentry);
    123
    124	if (dentry->d_name.len > (ORANGEFS_NAME_MAX - 1))
    125		return ERR_PTR(-ENAMETOOLONG);
    126
    127	new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
    128	if (!new_op)
    129		return ERR_PTR(-ENOMEM);
    130
    131	new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
    132
    133	gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d using parent %pU\n",
    134		     __FILE__,
    135		     __func__,
    136		     __LINE__,
    137		     &parent->refn.khandle);
    138	new_op->upcall.req.lookup.parent_refn = parent->refn;
    139
    140	strncpy(new_op->upcall.req.lookup.d_name, dentry->d_name.name,
    141		ORANGEFS_NAME_MAX - 1);
    142
    143	gossip_debug(GOSSIP_NAME_DEBUG,
    144		     "%s: doing lookup on %s under %pU,%d\n",
    145		     __func__,
    146		     new_op->upcall.req.lookup.d_name,
    147		     &new_op->upcall.req.lookup.parent_refn.khandle,
    148		     new_op->upcall.req.lookup.parent_refn.fs_id);
    149
    150	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
    151
    152	gossip_debug(GOSSIP_NAME_DEBUG,
    153		     "Lookup Got %pU, fsid %d (ret=%d)\n",
    154		     &new_op->downcall.resp.lookup.refn.khandle,
    155		     new_op->downcall.resp.lookup.refn.fs_id,
    156		     ret);
    157
    158	if (ret == 0) {
    159		orangefs_set_timeout(dentry);
    160		inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
    161	} else if (ret == -ENOENT) {
    162		inode = NULL;
    163	} else {
    164		/* must be a non-recoverable error */
    165		inode = ERR_PTR(ret);
    166	}
    167
    168	op_release(new_op);
    169	return d_splice_alias(inode, dentry);
    170}
    171
    172/* return 0 on success; non-zero otherwise */
    173static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
    174{
    175	struct inode *inode = dentry->d_inode;
    176	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
    177	struct orangefs_kernel_op_s *new_op;
    178	struct iattr iattr;
    179	int ret;
    180
    181	gossip_debug(GOSSIP_NAME_DEBUG,
    182		     "%s: called on %pd\n"
    183		     "  (inode %pU): Parent is %pU | fs_id %d\n",
    184		     __func__,
    185		     dentry,
    186		     get_khandle_from_ino(inode),
    187		     &parent->refn.khandle,
    188		     parent->refn.fs_id);
    189
    190	new_op = op_alloc(ORANGEFS_VFS_OP_REMOVE);
    191	if (!new_op)
    192		return -ENOMEM;
    193
    194	new_op->upcall.req.remove.parent_refn = parent->refn;
    195	strncpy(new_op->upcall.req.remove.d_name, dentry->d_name.name,
    196		ORANGEFS_NAME_MAX - 1);
    197
    198	ret = service_operation(new_op, "orangefs_unlink",
    199				get_interruptible_flag(inode));
    200
    201	gossip_debug(GOSSIP_NAME_DEBUG,
    202		     "%s: service_operation returned:%d:\n",
    203		     __func__,
    204		     ret);
    205
    206	op_release(new_op);
    207
    208	if (!ret) {
    209		drop_nlink(inode);
    210
    211		memset(&iattr, 0, sizeof iattr);
    212		iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
    213		iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
    214		__orangefs_setattr(dir, &iattr);
    215	}
    216	return ret;
    217}
    218
    219static int orangefs_symlink(struct user_namespace *mnt_userns,
    220		         struct inode *dir,
    221			 struct dentry *dentry,
    222			 const char *symname)
    223{
    224	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
    225	struct orangefs_kernel_op_s *new_op;
    226	struct orangefs_object_kref ref;
    227	struct inode *inode;
    228	struct iattr iattr;
    229	int mode = 0755;
    230	int ret;
    231
    232	gossip_debug(GOSSIP_NAME_DEBUG, "%s: called\n", __func__);
    233
    234	if (!symname)
    235		return -EINVAL;
    236
    237	if (strlen(symname)+1 > ORANGEFS_NAME_MAX)
    238		return -ENAMETOOLONG;
    239
    240	new_op = op_alloc(ORANGEFS_VFS_OP_SYMLINK);
    241	if (!new_op)
    242		return -ENOMEM;
    243
    244	new_op->upcall.req.sym.parent_refn = parent->refn;
    245
    246	fill_default_sys_attrs(new_op->upcall.req.sym.attributes,
    247			       ORANGEFS_TYPE_SYMLINK,
    248			       mode);
    249
    250	strncpy(new_op->upcall.req.sym.entry_name,
    251		dentry->d_name.name,
    252		ORANGEFS_NAME_MAX - 1);
    253	strncpy(new_op->upcall.req.sym.target, symname, ORANGEFS_NAME_MAX - 1);
    254
    255	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
    256
    257	gossip_debug(GOSSIP_NAME_DEBUG,
    258		     "Symlink Got ORANGEFS handle %pU on fsid %d (ret=%d)\n",
    259		     &new_op->downcall.resp.sym.refn.khandle,
    260		     new_op->downcall.resp.sym.refn.fs_id, ret);
    261
    262	if (ret < 0) {
    263		gossip_debug(GOSSIP_NAME_DEBUG,
    264			    "%s: failed with error code %d\n",
    265			    __func__, ret);
    266		goto out;
    267	}
    268
    269	ref = new_op->downcall.resp.sym.refn;
    270
    271	inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0, &ref);
    272	if (IS_ERR(inode)) {
    273		gossip_err
    274		    ("*** Failed to allocate orangefs symlink inode\n");
    275		ret = PTR_ERR(inode);
    276		goto out;
    277	}
    278	/*
    279	 * This is necessary because orangefs_inode_getattr will not
    280	 * re-read symlink size as it is impossible for it to change.
    281	 * Invalidating the cache does not help.  orangefs_new_inode
    282	 * does not set the correct size (it does not know symname).
    283	 */
    284	inode->i_size = strlen(symname);
    285
    286	gossip_debug(GOSSIP_NAME_DEBUG,
    287		     "Assigned symlink inode new number of %pU\n",
    288		     get_khandle_from_ino(inode));
    289
    290	d_instantiate_new(dentry, inode);
    291	orangefs_set_timeout(dentry);
    292
    293	gossip_debug(GOSSIP_NAME_DEBUG,
    294		     "Inode (Symlink) %pU -> %pd\n",
    295		     get_khandle_from_ino(inode),
    296		     dentry);
    297
    298	memset(&iattr, 0, sizeof iattr);
    299	iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
    300	iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
    301	__orangefs_setattr(dir, &iattr);
    302	ret = 0;
    303out:
    304	op_release(new_op);
    305	return ret;
    306}
    307
    308static int orangefs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
    309			  struct dentry *dentry, umode_t mode)
    310{
    311	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
    312	struct orangefs_kernel_op_s *new_op;
    313	struct orangefs_object_kref ref;
    314	struct inode *inode;
    315	struct iattr iattr;
    316	int ret;
    317
    318	new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR);
    319	if (!new_op)
    320		return -ENOMEM;
    321
    322	new_op->upcall.req.mkdir.parent_refn = parent->refn;
    323
    324	fill_default_sys_attrs(new_op->upcall.req.mkdir.attributes,
    325			      ORANGEFS_TYPE_DIRECTORY, mode);
    326
    327	strncpy(new_op->upcall.req.mkdir.d_name,
    328		dentry->d_name.name, ORANGEFS_NAME_MAX - 1);
    329
    330	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
    331
    332	gossip_debug(GOSSIP_NAME_DEBUG,
    333		     "Mkdir Got ORANGEFS handle %pU on fsid %d\n",
    334		     &new_op->downcall.resp.mkdir.refn.khandle,
    335		     new_op->downcall.resp.mkdir.refn.fs_id);
    336
    337	if (ret < 0) {
    338		gossip_debug(GOSSIP_NAME_DEBUG,
    339			     "%s: failed with error code %d\n",
    340			     __func__, ret);
    341		goto out;
    342	}
    343
    344	ref = new_op->downcall.resp.mkdir.refn;
    345
    346	inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0, &ref);
    347	if (IS_ERR(inode)) {
    348		gossip_err("*** Failed to allocate orangefs dir inode\n");
    349		ret = PTR_ERR(inode);
    350		goto out;
    351	}
    352
    353	gossip_debug(GOSSIP_NAME_DEBUG,
    354		     "Assigned dir inode new number of %pU\n",
    355		     get_khandle_from_ino(inode));
    356
    357	d_instantiate_new(dentry, inode);
    358	orangefs_set_timeout(dentry);
    359
    360	gossip_debug(GOSSIP_NAME_DEBUG,
    361		     "Inode (Directory) %pU -> %pd\n",
    362		     get_khandle_from_ino(inode),
    363		     dentry);
    364
    365	/*
    366	 * NOTE: we have no good way to keep nlink consistent for directories
    367	 * across clients; keep constant at 1.
    368	 */
    369	memset(&iattr, 0, sizeof iattr);
    370	iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
    371	iattr.ia_mtime = iattr.ia_ctime = current_time(dir);
    372	__orangefs_setattr(dir, &iattr);
    373out:
    374	op_release(new_op);
    375	return ret;
    376}
    377
    378static int orangefs_rename(struct user_namespace *mnt_userns,
    379			struct inode *old_dir,
    380			struct dentry *old_dentry,
    381			struct inode *new_dir,
    382			struct dentry *new_dentry,
    383			unsigned int flags)
    384{
    385	struct orangefs_kernel_op_s *new_op;
    386	struct iattr iattr;
    387	int ret;
    388
    389	if (flags)
    390		return -EINVAL;
    391
    392	gossip_debug(GOSSIP_NAME_DEBUG,
    393		     "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
    394		     old_dentry, new_dentry, d_count(new_dentry));
    395
    396	memset(&iattr, 0, sizeof iattr);
    397	iattr.ia_valid |= ATTR_MTIME | ATTR_CTIME;
    398	iattr.ia_mtime = iattr.ia_ctime = current_time(new_dir);
    399	__orangefs_setattr(new_dir, &iattr);
    400
    401	new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
    402	if (!new_op)
    403		return -EINVAL;
    404
    405	new_op->upcall.req.rename.old_parent_refn = ORANGEFS_I(old_dir)->refn;
    406	new_op->upcall.req.rename.new_parent_refn = ORANGEFS_I(new_dir)->refn;
    407
    408	strncpy(new_op->upcall.req.rename.d_old_name,
    409		old_dentry->d_name.name,
    410		ORANGEFS_NAME_MAX - 1);
    411	strncpy(new_op->upcall.req.rename.d_new_name,
    412		new_dentry->d_name.name,
    413		ORANGEFS_NAME_MAX - 1);
    414
    415	ret = service_operation(new_op,
    416				"orangefs_rename",
    417				get_interruptible_flag(old_dentry->d_inode));
    418
    419	gossip_debug(GOSSIP_NAME_DEBUG,
    420		     "orangefs_rename: got downcall status %d\n",
    421		     ret);
    422
    423	if (new_dentry->d_inode)
    424		new_dentry->d_inode->i_ctime = current_time(new_dentry->d_inode);
    425
    426	op_release(new_op);
    427	return ret;
    428}
    429
    430/* ORANGEFS implementation of VFS inode operations for directories */
    431const struct inode_operations orangefs_dir_inode_operations = {
    432	.lookup = orangefs_lookup,
    433	.get_acl = orangefs_get_acl,
    434	.set_acl = orangefs_set_acl,
    435	.create = orangefs_create,
    436	.unlink = orangefs_unlink,
    437	.symlink = orangefs_symlink,
    438	.mkdir = orangefs_mkdir,
    439	.rmdir = orangefs_unlink,
    440	.rename = orangefs_rename,
    441	.setattr = orangefs_setattr,
    442	.getattr = orangefs_getattr,
    443	.listxattr = orangefs_listxattr,
    444	.permission = orangefs_permission,
    445	.update_time = orangefs_update_time,
    446};