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 */
orangefs_create(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,bool exclusive)18 static 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;
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 */
orangefs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)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 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 */
orangefs_unlink(struct inode * dir,struct dentry * dentry)170 static 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
orangefs_symlink(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,const char * symname)215 static 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;
295 out:
296 op_release(new_op);
297 return ret;
298 }
299
orangefs_mkdir(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode)300 static 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);
363 out:
364 op_release(new_op);
365 return ERR_PTR(ret);
366 }
367
orangefs_rename(struct mnt_idmap * idmap,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)368 static 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 */
417 const 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 };
433