GNU Linux-libre 4.19.286-gnu1
[releases.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          * This is necessary because orangefs_inode_getattr will not
283          * re-read symlink size as it is impossible for it to change.
284          * Invalidating the cache does not help.  orangefs_new_inode
285          * does not set the correct size (it does not know symname).
286          */
287         inode->i_size = strlen(symname);
288
289         gossip_debug(GOSSIP_NAME_DEBUG,
290                      "Assigned symlink inode new number of %pU\n",
291                      get_khandle_from_ino(inode));
292
293         d_instantiate_new(dentry, inode);
294         orangefs_set_timeout(dentry);
295         ORANGEFS_I(inode)->getattr_time = jiffies - 1;
296         ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS;
297
298         gossip_debug(GOSSIP_NAME_DEBUG,
299                      "Inode (Symlink) %pU -> %pd\n",
300                      get_khandle_from_ino(inode),
301                      dentry);
302
303         dir->i_mtime = dir->i_ctime = current_time(dir);
304         memset(&iattr, 0, sizeof iattr);
305         iattr.ia_valid |= ATTR_MTIME;
306         orangefs_inode_setattr(dir, &iattr);
307         mark_inode_dirty_sync(dir);
308         ret = 0;
309 out:
310         return ret;
311 }
312
313 static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
314 {
315         struct orangefs_inode_s *parent = ORANGEFS_I(dir);
316         struct orangefs_kernel_op_s *new_op;
317         struct orangefs_object_kref ref;
318         struct inode *inode;
319         struct iattr iattr;
320         int ret;
321
322         new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR);
323         if (!new_op)
324                 return -ENOMEM;
325
326         new_op->upcall.req.mkdir.parent_refn = parent->refn;
327
328         fill_default_sys_attrs(new_op->upcall.req.mkdir.attributes,
329                               ORANGEFS_TYPE_DIRECTORY, mode);
330
331         strncpy(new_op->upcall.req.mkdir.d_name,
332                 dentry->d_name.name, ORANGEFS_NAME_MAX - 1);
333
334         ret = service_operation(new_op, __func__, get_interruptible_flag(dir));
335
336         gossip_debug(GOSSIP_NAME_DEBUG,
337                      "Mkdir Got ORANGEFS handle %pU on fsid %d\n",
338                      &new_op->downcall.resp.mkdir.refn.khandle,
339                      new_op->downcall.resp.mkdir.refn.fs_id);
340
341         if (ret < 0) {
342                 gossip_debug(GOSSIP_NAME_DEBUG,
343                              "%s: failed with error code %d\n",
344                              __func__, ret);
345                 goto out;
346         }
347
348         ref = new_op->downcall.resp.mkdir.refn;
349         op_release(new_op);
350
351         inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0, &ref);
352         if (IS_ERR(inode)) {
353                 gossip_err("*** Failed to allocate orangefs dir inode\n");
354                 ret = PTR_ERR(inode);
355                 goto out;
356         }
357
358         gossip_debug(GOSSIP_NAME_DEBUG,
359                      "Assigned dir inode new number of %pU\n",
360                      get_khandle_from_ino(inode));
361
362         d_instantiate_new(dentry, inode);
363         orangefs_set_timeout(dentry);
364         ORANGEFS_I(inode)->getattr_time = jiffies - 1;
365         ORANGEFS_I(inode)->getattr_mask = STATX_BASIC_STATS;
366
367         gossip_debug(GOSSIP_NAME_DEBUG,
368                      "Inode (Directory) %pU -> %pd\n",
369                      get_khandle_from_ino(inode),
370                      dentry);
371
372         /*
373          * NOTE: we have no good way to keep nlink consistent for directories
374          * across clients; keep constant at 1.
375          */
376         dir->i_mtime = dir->i_ctime = current_time(dir);
377         memset(&iattr, 0, sizeof iattr);
378         iattr.ia_valid |= ATTR_MTIME;
379         orangefs_inode_setattr(dir, &iattr);
380         mark_inode_dirty_sync(dir);
381 out:
382         return ret;
383 }
384
385 static int orangefs_rename(struct inode *old_dir,
386                         struct dentry *old_dentry,
387                         struct inode *new_dir,
388                         struct dentry *new_dentry,
389                         unsigned int flags)
390 {
391         struct orangefs_kernel_op_s *new_op;
392         int ret;
393
394         if (flags)
395                 return -EINVAL;
396
397         gossip_debug(GOSSIP_NAME_DEBUG,
398                      "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
399                      old_dentry, new_dentry, d_count(new_dentry));
400
401         ORANGEFS_I(new_dentry->d_parent->d_inode)->getattr_time = jiffies - 1;
402
403         new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
404         if (!new_op)
405                 return -EINVAL;
406
407         new_op->upcall.req.rename.old_parent_refn = ORANGEFS_I(old_dir)->refn;
408         new_op->upcall.req.rename.new_parent_refn = ORANGEFS_I(new_dir)->refn;
409
410         strncpy(new_op->upcall.req.rename.d_old_name,
411                 old_dentry->d_name.name,
412                 ORANGEFS_NAME_MAX - 1);
413         strncpy(new_op->upcall.req.rename.d_new_name,
414                 new_dentry->d_name.name,
415                 ORANGEFS_NAME_MAX - 1);
416
417         ret = service_operation(new_op,
418                                 "orangefs_rename",
419                                 get_interruptible_flag(old_dentry->d_inode));
420
421         gossip_debug(GOSSIP_NAME_DEBUG,
422                      "orangefs_rename: got downcall status %d\n",
423                      ret);
424
425         if (new_dentry->d_inode)
426                 new_dentry->d_inode->i_ctime = current_time(new_dentry->d_inode);
427
428         op_release(new_op);
429         return ret;
430 }
431
432 /* ORANGEFS implementation of VFS inode operations for directories */
433 const struct inode_operations orangefs_dir_inode_operations = {
434         .lookup = orangefs_lookup,
435         .get_acl = orangefs_get_acl,
436         .set_acl = orangefs_set_acl,
437         .create = orangefs_create,
438         .unlink = orangefs_unlink,
439         .symlink = orangefs_symlink,
440         .mkdir = orangefs_mkdir,
441         .rmdir = orangefs_unlink,
442         .rename = orangefs_rename,
443         .setattr = orangefs_setattr,
444         .getattr = orangefs_getattr,
445         .listxattr = orangefs_listxattr,
446         .permission = orangefs_permission,
447         .update_time = orangefs_update_time,
448 };