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