xref: /openbmc/linux/fs/orangefs/namei.c (revision b24413180f5600bcb3bb70fbed5cf186b60864bd)
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  */
18 static int orangefs_create(struct inode *dir,
19 			struct dentry *dentry,
20 			umode_t mode,
21 			bool exclusive)
22 {
23 	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
24 	struct orangefs_kernel_op_s *new_op;
25 	struct inode *inode;
26 	int ret;
27 
28 	gossip_debug(GOSSIP_NAME_DEBUG, "%s: %pd\n",
29 		     __func__,
30 		     dentry);
31 
32 	new_op = op_alloc(ORANGEFS_VFS_OP_CREATE);
33 	if (!new_op)
34 		return -ENOMEM;
35 
36 	new_op->upcall.req.create.parent_refn = parent->refn;
37 
38 	fill_default_sys_attrs(new_op->upcall.req.create.attributes,
39 			       ORANGEFS_TYPE_METAFILE, mode);
40 
41 	strncpy(new_op->upcall.req.create.d_name,
42 		dentry->d_name.name, ORANGEFS_NAME_MAX);
43 
44 	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
45 
46 	gossip_debug(GOSSIP_NAME_DEBUG,
47 		     "%s: %pd: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n",
48 		     __func__,
49 		     dentry,
50 		     &new_op->downcall.resp.create.refn.khandle,
51 		     new_op->downcall.resp.create.refn.fs_id,
52 		     new_op,
53 		     ret);
54 
55 	if (ret < 0)
56 		goto out;
57 
58 	inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0,
59 				&new_op->downcall.resp.create.refn);
60 	if (IS_ERR(inode)) {
61 		gossip_err("%s: Failed to allocate inode for file :%pd:\n",
62 			   __func__,
63 			   dentry);
64 		ret = PTR_ERR(inode);
65 		goto out;
66 	}
67 
68 	gossip_debug(GOSSIP_NAME_DEBUG,
69 		     "%s: Assigned inode :%pU: for file :%pd:\n",
70 		     __func__,
71 		     get_khandle_from_ino(inode),
72 		     dentry);
73 
74 	d_instantiate(dentry, inode);
75 	unlock_new_inode(inode);
76 	orangefs_set_timeout(dentry);
77 	ORANGEFS_I(inode)->getattr_time = jiffies - 1;
78 	ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS;
79 
80 	gossip_debug(GOSSIP_NAME_DEBUG,
81 		     "%s: dentry instantiated for %pd\n",
82 		     __func__,
83 		     dentry);
84 
85 	SetMtimeFlag(parent);
86 	dir->i_mtime = dir->i_ctime = current_time(dir);
87 	mark_inode_dirty_sync(dir);
88 	ret = 0;
89 out:
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  */
103 static 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 	struct dentry *res;
110 	int ret = -EINVAL;
111 
112 	/*
113 	 * in theory we could skip a lookup here (if the intent is to
114 	 * create) in order to avoid a potentially failed lookup, but
115 	 * leaving it in can skip a valid lookup and try to create a file
116 	 * that already exists (e.g. the vfs already handles checking for
117 	 * -EEXIST on O_EXCL opens, which is broken if we skip this lookup
118 	 * in the create path)
119 	 */
120 	gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %pd\n",
121 		     __func__, dentry);
122 
123 	if (dentry->d_name.len > (ORANGEFS_NAME_MAX - 1))
124 		return ERR_PTR(-ENAMETOOLONG);
125 
126 	new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
127 	if (!new_op)
128 		return ERR_PTR(-ENOMEM);
129 
130 	new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
131 
132 	gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d using parent %pU\n",
133 		     __FILE__,
134 		     __func__,
135 		     __LINE__,
136 		     &parent->refn.khandle);
137 	new_op->upcall.req.lookup.parent_refn = parent->refn;
138 
139 	strncpy(new_op->upcall.req.lookup.d_name, dentry->d_name.name,
140 		ORANGEFS_NAME_MAX);
141 
142 	gossip_debug(GOSSIP_NAME_DEBUG,
143 		     "%s: doing lookup on %s under %pU,%d\n",
144 		     __func__,
145 		     new_op->upcall.req.lookup.d_name,
146 		     &new_op->upcall.req.lookup.parent_refn.khandle,
147 		     new_op->upcall.req.lookup.parent_refn.fs_id);
148 
149 	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
150 
151 	gossip_debug(GOSSIP_NAME_DEBUG,
152 		     "Lookup Got %pU, fsid %d (ret=%d)\n",
153 		     &new_op->downcall.resp.lookup.refn.khandle,
154 		     new_op->downcall.resp.lookup.refn.fs_id,
155 		     ret);
156 
157 	if (ret < 0) {
158 		if (ret == -ENOENT) {
159 			/*
160 			 * if no inode was found, add a negative dentry to
161 			 * dcache anyway; if we don't, we don't hold expected
162 			 * lookup semantics and we most noticeably break
163 			 * during directory renames.
164 			 *
165 			 * however, if the operation failed or exited, do not
166 			 * add the dentry (e.g. in the case that a touch is
167 			 * issued on a file that already exists that was
168 			 * interrupted during this lookup -- no need to add
169 			 * another negative dentry for an existing file)
170 			 */
171 
172 			gossip_debug(GOSSIP_NAME_DEBUG,
173 				     "orangefs_lookup: Adding *negative* dentry "
174 				     "%p for %pd\n",
175 				     dentry,
176 				     dentry);
177 
178 			d_add(dentry, NULL);
179 			res = NULL;
180 			goto out;
181 		}
182 
183 		/* must be a non-recoverable error */
184 		res = ERR_PTR(ret);
185 		goto out;
186 	}
187 
188 	orangefs_set_timeout(dentry);
189 
190 	inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
191 	if (IS_ERR(inode)) {
192 		gossip_debug(GOSSIP_NAME_DEBUG,
193 			"error %ld from iget\n", PTR_ERR(inode));
194 		res = ERR_CAST(inode);
195 		goto out;
196 	}
197 
198 	gossip_debug(GOSSIP_NAME_DEBUG,
199 		     "%s:%s:%d "
200 		     "Found good inode [%lu] with count [%d]\n",
201 		     __FILE__,
202 		     __func__,
203 		     __LINE__,
204 		     inode->i_ino,
205 		     (int)atomic_read(&inode->i_count));
206 
207 	/* update dentry/inode pair into dcache */
208 	res = d_splice_alias(inode, dentry);
209 
210 	gossip_debug(GOSSIP_NAME_DEBUG,
211 		     "Lookup success (inode ct = %d)\n",
212 		     (int)atomic_read(&inode->i_count));
213 out:
214 	op_release(new_op);
215 	return res;
216 }
217 
218 /* return 0 on success; non-zero otherwise */
219 static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
220 {
221 	struct inode *inode = dentry->d_inode;
222 	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
223 	struct orangefs_kernel_op_s *new_op;
224 	int ret;
225 
226 	gossip_debug(GOSSIP_NAME_DEBUG,
227 		     "%s: called on %pd\n"
228 		     "  (inode %pU): Parent is %pU | fs_id %d\n",
229 		     __func__,
230 		     dentry,
231 		     get_khandle_from_ino(inode),
232 		     &parent->refn.khandle,
233 		     parent->refn.fs_id);
234 
235 	new_op = op_alloc(ORANGEFS_VFS_OP_REMOVE);
236 	if (!new_op)
237 		return -ENOMEM;
238 
239 	new_op->upcall.req.remove.parent_refn = parent->refn;
240 	strncpy(new_op->upcall.req.remove.d_name, dentry->d_name.name,
241 		ORANGEFS_NAME_MAX);
242 
243 	ret = service_operation(new_op, "orangefs_unlink",
244 				get_interruptible_flag(inode));
245 
246 	gossip_debug(GOSSIP_NAME_DEBUG,
247 		     "%s: service_operation returned:%d:\n",
248 		     __func__,
249 		     ret);
250 
251 	op_release(new_op);
252 
253 	if (!ret) {
254 		drop_nlink(inode);
255 
256 		SetMtimeFlag(parent);
257 		dir->i_mtime = dir->i_ctime = current_time(dir);
258 		mark_inode_dirty_sync(dir);
259 	}
260 	return ret;
261 }
262 
263 static int orangefs_symlink(struct inode *dir,
264 			 struct dentry *dentry,
265 			 const char *symname)
266 {
267 	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
268 	struct orangefs_kernel_op_s *new_op;
269 	struct inode *inode;
270 	int mode = 755;
271 	int ret;
272 
273 	gossip_debug(GOSSIP_NAME_DEBUG, "%s: called\n", __func__);
274 
275 	if (!symname)
276 		return -EINVAL;
277 
278 	if (strlen(symname)+1 > ORANGEFS_NAME_MAX)
279 		return -ENAMETOOLONG;
280 
281 	new_op = op_alloc(ORANGEFS_VFS_OP_SYMLINK);
282 	if (!new_op)
283 		return -ENOMEM;
284 
285 	new_op->upcall.req.sym.parent_refn = parent->refn;
286 
287 	fill_default_sys_attrs(new_op->upcall.req.sym.attributes,
288 			       ORANGEFS_TYPE_SYMLINK,
289 			       mode);
290 
291 	strncpy(new_op->upcall.req.sym.entry_name,
292 		dentry->d_name.name,
293 		ORANGEFS_NAME_MAX);
294 	strncpy(new_op->upcall.req.sym.target, symname, ORANGEFS_NAME_MAX);
295 
296 	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
297 
298 	gossip_debug(GOSSIP_NAME_DEBUG,
299 		     "Symlink Got ORANGEFS handle %pU on fsid %d (ret=%d)\n",
300 		     &new_op->downcall.resp.sym.refn.khandle,
301 		     new_op->downcall.resp.sym.refn.fs_id, ret);
302 
303 	if (ret < 0) {
304 		gossip_debug(GOSSIP_NAME_DEBUG,
305 			    "%s: failed with error code %d\n",
306 			    __func__, ret);
307 		goto out;
308 	}
309 
310 	inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0,
311 				&new_op->downcall.resp.sym.refn);
312 	if (IS_ERR(inode)) {
313 		gossip_err
314 		    ("*** Failed to allocate orangefs symlink inode\n");
315 		ret = PTR_ERR(inode);
316 		goto out;
317 	}
318 
319 	gossip_debug(GOSSIP_NAME_DEBUG,
320 		     "Assigned symlink inode new number of %pU\n",
321 		     get_khandle_from_ino(inode));
322 
323 	d_instantiate(dentry, inode);
324 	unlock_new_inode(inode);
325 	orangefs_set_timeout(dentry);
326 	ORANGEFS_I(inode)->getattr_time = jiffies - 1;
327 	ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS;
328 
329 	gossip_debug(GOSSIP_NAME_DEBUG,
330 		     "Inode (Symlink) %pU -> %pd\n",
331 		     get_khandle_from_ino(inode),
332 		     dentry);
333 
334 	SetMtimeFlag(parent);
335 	dir->i_mtime = dir->i_ctime = current_time(dir);
336 	mark_inode_dirty_sync(dir);
337 	ret = 0;
338 out:
339 	op_release(new_op);
340 	return ret;
341 }
342 
343 static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
344 {
345 	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
346 	struct orangefs_kernel_op_s *new_op;
347 	struct inode *inode;
348 	int ret;
349 
350 	new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR);
351 	if (!new_op)
352 		return -ENOMEM;
353 
354 	new_op->upcall.req.mkdir.parent_refn = parent->refn;
355 
356 	fill_default_sys_attrs(new_op->upcall.req.mkdir.attributes,
357 			      ORANGEFS_TYPE_DIRECTORY, mode);
358 
359 	strncpy(new_op->upcall.req.mkdir.d_name,
360 		dentry->d_name.name, ORANGEFS_NAME_MAX);
361 
362 	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
363 
364 	gossip_debug(GOSSIP_NAME_DEBUG,
365 		     "Mkdir Got ORANGEFS handle %pU on fsid %d\n",
366 		     &new_op->downcall.resp.mkdir.refn.khandle,
367 		     new_op->downcall.resp.mkdir.refn.fs_id);
368 
369 	if (ret < 0) {
370 		gossip_debug(GOSSIP_NAME_DEBUG,
371 			     "%s: failed with error code %d\n",
372 			     __func__, ret);
373 		goto out;
374 	}
375 
376 	inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0,
377 				&new_op->downcall.resp.mkdir.refn);
378 	if (IS_ERR(inode)) {
379 		gossip_err("*** Failed to allocate orangefs dir inode\n");
380 		ret = PTR_ERR(inode);
381 		goto out;
382 	}
383 
384 	gossip_debug(GOSSIP_NAME_DEBUG,
385 		     "Assigned dir inode new number of %pU\n",
386 		     get_khandle_from_ino(inode));
387 
388 	d_instantiate(dentry, inode);
389 	unlock_new_inode(inode);
390 	orangefs_set_timeout(dentry);
391 	ORANGEFS_I(inode)->getattr_time = jiffies - 1;
392 	ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS;
393 
394 	gossip_debug(GOSSIP_NAME_DEBUG,
395 		     "Inode (Directory) %pU -> %pd\n",
396 		     get_khandle_from_ino(inode),
397 		     dentry);
398 
399 	/*
400 	 * NOTE: we have no good way to keep nlink consistent for directories
401 	 * across clients; keep constant at 1.
402 	 */
403 	SetMtimeFlag(parent);
404 	dir->i_mtime = dir->i_ctime = current_time(dir);
405 	mark_inode_dirty_sync(dir);
406 out:
407 	op_release(new_op);
408 	return ret;
409 }
410 
411 static int orangefs_rename(struct inode *old_dir,
412 			struct dentry *old_dentry,
413 			struct inode *new_dir,
414 			struct dentry *new_dentry,
415 			unsigned int flags)
416 {
417 	struct orangefs_kernel_op_s *new_op;
418 	int ret;
419 
420 	if (flags)
421 		return -EINVAL;
422 
423 	gossip_debug(GOSSIP_NAME_DEBUG,
424 		     "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
425 		     old_dentry, new_dentry, d_count(new_dentry));
426 
427 	ORANGEFS_I(new_dentry->d_parent->d_inode)->getattr_time = jiffies - 1;
428 
429 	new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
430 	if (!new_op)
431 		return -EINVAL;
432 
433 	new_op->upcall.req.rename.old_parent_refn = ORANGEFS_I(old_dir)->refn;
434 	new_op->upcall.req.rename.new_parent_refn = ORANGEFS_I(new_dir)->refn;
435 
436 	strncpy(new_op->upcall.req.rename.d_old_name,
437 		old_dentry->d_name.name,
438 		ORANGEFS_NAME_MAX);
439 	strncpy(new_op->upcall.req.rename.d_new_name,
440 		new_dentry->d_name.name,
441 		ORANGEFS_NAME_MAX);
442 
443 	ret = service_operation(new_op,
444 				"orangefs_rename",
445 				get_interruptible_flag(old_dentry->d_inode));
446 
447 	gossip_debug(GOSSIP_NAME_DEBUG,
448 		     "orangefs_rename: got downcall status %d\n",
449 		     ret);
450 
451 	if (new_dentry->d_inode)
452 		new_dentry->d_inode->i_ctime = current_time(new_dentry->d_inode);
453 
454 	op_release(new_op);
455 	return ret;
456 }
457 
458 /* ORANGEFS implementation of VFS inode operations for directories */
459 const struct inode_operations orangefs_dir_inode_operations = {
460 	.lookup = orangefs_lookup,
461 	.get_acl = orangefs_get_acl,
462 	.set_acl = orangefs_set_acl,
463 	.create = orangefs_create,
464 	.unlink = orangefs_unlink,
465 	.symlink = orangefs_symlink,
466 	.mkdir = orangefs_mkdir,
467 	.rmdir = orangefs_unlink,
468 	.rename = orangefs_rename,
469 	.setattr = orangefs_setattr,
470 	.getattr = orangefs_getattr,
471 	.listxattr = orangefs_listxattr,
472 	.permission = orangefs_permission,
473 };
474