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