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