File Index
Files and directories
Sign in
FILE

namei.c

File preview with syntax highlighting.

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