[PATCH] fuse: more flexible caching
[deliverable/linux.git] / fs / fuse / dir.c
CommitLineData
e5e5558e
MS
1/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10
11#include <linux/pagemap.h>
12#include <linux/file.h>
13#include <linux/gfp.h>
14#include <linux/sched.h>
15#include <linux/namei.h>
16
17static inline unsigned long time_to_jiffies(unsigned long sec,
18 unsigned long nsec)
19{
20 struct timespec ts = {sec, nsec};
21 return jiffies + timespec_to_jiffies(&ts);
22}
23
24static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
25 struct dentry *entry,
26 struct fuse_entry_out *outarg)
27{
28 req->in.h.opcode = FUSE_LOOKUP;
29 req->in.h.nodeid = get_node_id(dir);
30 req->inode = dir;
31 req->in.numargs = 1;
32 req->in.args[0].size = entry->d_name.len + 1;
33 req->in.args[0].value = entry->d_name.name;
34 req->out.numargs = 1;
35 req->out.args[0].size = sizeof(struct fuse_entry_out);
36 req->out.args[0].value = outarg;
37}
38
39static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
40{
41 if (!entry->d_inode || is_bad_inode(entry->d_inode))
42 return 0;
43 else if (time_after(jiffies, entry->d_time)) {
44 int err;
e5e5558e
MS
45 struct fuse_entry_out outarg;
46 struct inode *inode = entry->d_inode;
47 struct fuse_inode *fi = get_fuse_inode(inode);
48 struct fuse_conn *fc = get_fuse_conn(inode);
49 struct fuse_req *req = fuse_get_request_nonint(fc);
50 if (!req)
51 return 0;
52
53 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
54 request_send_nonint(fc, req);
e5e5558e 55 err = req->out.h.error;
9e6268db
MS
56 if (!err) {
57 if (outarg.nodeid != get_node_id(inode)) {
58 fuse_send_forget(fc, req, outarg.nodeid, 1);
59 return 0;
60 }
61 fi->nlookup ++;
62 }
e5e5558e 63 fuse_put_request(fc, req);
9e6268db 64 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
e5e5558e
MS
65 return 0;
66
67 fuse_change_attributes(inode, &outarg.attr);
e5e5558e
MS
68 entry->d_time = time_to_jiffies(outarg.entry_valid,
69 outarg.entry_valid_nsec);
70 fi->i_time = time_to_jiffies(outarg.attr_valid,
71 outarg.attr_valid_nsec);
72 }
73 return 1;
74}
75
76static struct dentry_operations fuse_dentry_operations = {
77 .d_revalidate = fuse_dentry_revalidate,
78};
79
80static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
81 struct inode **inodep)
82{
83 int err;
e5e5558e
MS
84 struct fuse_entry_out outarg;
85 struct inode *inode = NULL;
86 struct fuse_conn *fc = get_fuse_conn(dir);
87 struct fuse_req *req;
88
89 if (entry->d_name.len > FUSE_NAME_MAX)
90 return -ENAMETOOLONG;
91
92 req = fuse_get_request(fc);
93 if (!req)
94 return -ERESTARTNOINTR;
95
96 fuse_lookup_init(req, dir, entry, &outarg);
97 request_send(fc, req);
e5e5558e
MS
98 err = req->out.h.error;
99 if (!err) {
100 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
9e6268db 101 &outarg.attr);
e5e5558e 102 if (!inode) {
9e6268db 103 fuse_send_forget(fc, req, outarg.nodeid, 1);
e5e5558e
MS
104 return -ENOMEM;
105 }
106 }
107 fuse_put_request(fc, req);
108 if (err && err != -ENOENT)
109 return err;
110
111 if (inode) {
112 struct fuse_inode *fi = get_fuse_inode(inode);
113 entry->d_time = time_to_jiffies(outarg.entry_valid,
114 outarg.entry_valid_nsec);
115 fi->i_time = time_to_jiffies(outarg.attr_valid,
116 outarg.attr_valid_nsec);
117 }
118
119 entry->d_op = &fuse_dentry_operations;
120 *inodep = inode;
121 return 0;
122}
123
9e6268db
MS
124void fuse_invalidate_attr(struct inode *inode)
125{
126 get_fuse_inode(inode)->i_time = jiffies - 1;
127}
128
129static void fuse_invalidate_entry(struct dentry *entry)
130{
131 d_invalidate(entry);
132 entry->d_time = jiffies - 1;
133}
134
135static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
136 struct inode *dir, struct dentry *entry,
137 int mode)
138{
139 struct fuse_entry_out outarg;
140 struct inode *inode;
141 struct fuse_inode *fi;
142 int err;
143
144 req->in.h.nodeid = get_node_id(dir);
145 req->inode = dir;
146 req->out.numargs = 1;
147 req->out.args[0].size = sizeof(outarg);
148 req->out.args[0].value = &outarg;
149 request_send(fc, req);
150 err = req->out.h.error;
151 if (err) {
152 fuse_put_request(fc, req);
153 return err;
154 }
155 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
156 &outarg.attr);
157 if (!inode) {
158 fuse_send_forget(fc, req, outarg.nodeid, 1);
159 return -ENOMEM;
160 }
161 fuse_put_request(fc, req);
162
163 /* Don't allow userspace to do really stupid things... */
164 if ((inode->i_mode ^ mode) & S_IFMT) {
165 iput(inode);
166 return -EIO;
167 }
168
169 entry->d_time = time_to_jiffies(outarg.entry_valid,
170 outarg.entry_valid_nsec);
171
172 fi = get_fuse_inode(inode);
173 fi->i_time = time_to_jiffies(outarg.attr_valid,
174 outarg.attr_valid_nsec);
175
176 d_instantiate(entry, inode);
177 fuse_invalidate_attr(dir);
178 return 0;
179}
180
181static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
182 dev_t rdev)
183{
184 struct fuse_mknod_in inarg;
185 struct fuse_conn *fc = get_fuse_conn(dir);
186 struct fuse_req *req = fuse_get_request(fc);
187 if (!req)
188 return -ERESTARTNOINTR;
189
190 memset(&inarg, 0, sizeof(inarg));
191 inarg.mode = mode;
192 inarg.rdev = new_encode_dev(rdev);
193 req->in.h.opcode = FUSE_MKNOD;
194 req->in.numargs = 2;
195 req->in.args[0].size = sizeof(inarg);
196 req->in.args[0].value = &inarg;
197 req->in.args[1].size = entry->d_name.len + 1;
198 req->in.args[1].value = entry->d_name.name;
199 return create_new_entry(fc, req, dir, entry, mode);
200}
201
202static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
203 struct nameidata *nd)
204{
205 return fuse_mknod(dir, entry, mode, 0);
206}
207
208static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
209{
210 struct fuse_mkdir_in inarg;
211 struct fuse_conn *fc = get_fuse_conn(dir);
212 struct fuse_req *req = fuse_get_request(fc);
213 if (!req)
214 return -ERESTARTNOINTR;
215
216 memset(&inarg, 0, sizeof(inarg));
217 inarg.mode = mode;
218 req->in.h.opcode = FUSE_MKDIR;
219 req->in.numargs = 2;
220 req->in.args[0].size = sizeof(inarg);
221 req->in.args[0].value = &inarg;
222 req->in.args[1].size = entry->d_name.len + 1;
223 req->in.args[1].value = entry->d_name.name;
224 return create_new_entry(fc, req, dir, entry, S_IFDIR);
225}
226
227static int fuse_symlink(struct inode *dir, struct dentry *entry,
228 const char *link)
229{
230 struct fuse_conn *fc = get_fuse_conn(dir);
231 unsigned len = strlen(link) + 1;
232 struct fuse_req *req;
233
234 if (len > FUSE_SYMLINK_MAX)
235 return -ENAMETOOLONG;
236
237 req = fuse_get_request(fc);
238 if (!req)
239 return -ERESTARTNOINTR;
240
241 req->in.h.opcode = FUSE_SYMLINK;
242 req->in.numargs = 2;
243 req->in.args[0].size = entry->d_name.len + 1;
244 req->in.args[0].value = entry->d_name.name;
245 req->in.args[1].size = len;
246 req->in.args[1].value = link;
247 return create_new_entry(fc, req, dir, entry, S_IFLNK);
248}
249
250static int fuse_unlink(struct inode *dir, struct dentry *entry)
251{
252 int err;
253 struct fuse_conn *fc = get_fuse_conn(dir);
254 struct fuse_req *req = fuse_get_request(fc);
255 if (!req)
256 return -ERESTARTNOINTR;
257
258 req->in.h.opcode = FUSE_UNLINK;
259 req->in.h.nodeid = get_node_id(dir);
260 req->inode = dir;
261 req->in.numargs = 1;
262 req->in.args[0].size = entry->d_name.len + 1;
263 req->in.args[0].value = entry->d_name.name;
264 request_send(fc, req);
265 err = req->out.h.error;
266 fuse_put_request(fc, req);
267 if (!err) {
268 struct inode *inode = entry->d_inode;
269
270 /* Set nlink to zero so the inode can be cleared, if
271 the inode does have more links this will be
272 discovered at the next lookup/getattr */
273 inode->i_nlink = 0;
274 fuse_invalidate_attr(inode);
275 fuse_invalidate_attr(dir);
276 } else if (err == -EINTR)
277 fuse_invalidate_entry(entry);
278 return err;
279}
280
281static int fuse_rmdir(struct inode *dir, struct dentry *entry)
282{
283 int err;
284 struct fuse_conn *fc = get_fuse_conn(dir);
285 struct fuse_req *req = fuse_get_request(fc);
286 if (!req)
287 return -ERESTARTNOINTR;
288
289 req->in.h.opcode = FUSE_RMDIR;
290 req->in.h.nodeid = get_node_id(dir);
291 req->inode = dir;
292 req->in.numargs = 1;
293 req->in.args[0].size = entry->d_name.len + 1;
294 req->in.args[0].value = entry->d_name.name;
295 request_send(fc, req);
296 err = req->out.h.error;
297 fuse_put_request(fc, req);
298 if (!err) {
299 entry->d_inode->i_nlink = 0;
300 fuse_invalidate_attr(dir);
301 } else if (err == -EINTR)
302 fuse_invalidate_entry(entry);
303 return err;
304}
305
306static int fuse_rename(struct inode *olddir, struct dentry *oldent,
307 struct inode *newdir, struct dentry *newent)
308{
309 int err;
310 struct fuse_rename_in inarg;
311 struct fuse_conn *fc = get_fuse_conn(olddir);
312 struct fuse_req *req = fuse_get_request(fc);
313 if (!req)
314 return -ERESTARTNOINTR;
315
316 memset(&inarg, 0, sizeof(inarg));
317 inarg.newdir = get_node_id(newdir);
318 req->in.h.opcode = FUSE_RENAME;
319 req->in.h.nodeid = get_node_id(olddir);
320 req->inode = olddir;
321 req->inode2 = newdir;
322 req->in.numargs = 3;
323 req->in.args[0].size = sizeof(inarg);
324 req->in.args[0].value = &inarg;
325 req->in.args[1].size = oldent->d_name.len + 1;
326 req->in.args[1].value = oldent->d_name.name;
327 req->in.args[2].size = newent->d_name.len + 1;
328 req->in.args[2].value = newent->d_name.name;
329 request_send(fc, req);
330 err = req->out.h.error;
331 fuse_put_request(fc, req);
332 if (!err) {
333 fuse_invalidate_attr(olddir);
334 if (olddir != newdir)
335 fuse_invalidate_attr(newdir);
336 } else if (err == -EINTR) {
337 /* If request was interrupted, DEITY only knows if the
338 rename actually took place. If the invalidation
339 fails (e.g. some process has CWD under the renamed
340 directory), then there can be inconsistency between
341 the dcache and the real filesystem. Tough luck. */
342 fuse_invalidate_entry(oldent);
343 if (newent->d_inode)
344 fuse_invalidate_entry(newent);
345 }
346
347 return err;
348}
349
350static int fuse_link(struct dentry *entry, struct inode *newdir,
351 struct dentry *newent)
352{
353 int err;
354 struct fuse_link_in inarg;
355 struct inode *inode = entry->d_inode;
356 struct fuse_conn *fc = get_fuse_conn(inode);
357 struct fuse_req *req = fuse_get_request(fc);
358 if (!req)
359 return -ERESTARTNOINTR;
360
361 memset(&inarg, 0, sizeof(inarg));
362 inarg.oldnodeid = get_node_id(inode);
363 req->in.h.opcode = FUSE_LINK;
364 req->inode2 = inode;
365 req->in.numargs = 2;
366 req->in.args[0].size = sizeof(inarg);
367 req->in.args[0].value = &inarg;
368 req->in.args[1].size = newent->d_name.len + 1;
369 req->in.args[1].value = newent->d_name.name;
370 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
371 /* Contrary to "normal" filesystems it can happen that link
372 makes two "logical" inodes point to the same "physical"
373 inode. We invalidate the attributes of the old one, so it
374 will reflect changes in the backing inode (link count,
375 etc.)
376 */
377 if (!err || err == -EINTR)
378 fuse_invalidate_attr(inode);
379 return err;
380}
381
e5e5558e
MS
382int fuse_do_getattr(struct inode *inode)
383{
384 int err;
385 struct fuse_attr_out arg;
386 struct fuse_conn *fc = get_fuse_conn(inode);
387 struct fuse_req *req = fuse_get_request(fc);
388 if (!req)
389 return -ERESTARTNOINTR;
390
391 req->in.h.opcode = FUSE_GETATTR;
392 req->in.h.nodeid = get_node_id(inode);
393 req->inode = inode;
394 req->out.numargs = 1;
395 req->out.args[0].size = sizeof(arg);
396 req->out.args[0].value = &arg;
397 request_send(fc, req);
398 err = req->out.h.error;
399 fuse_put_request(fc, req);
400 if (!err) {
401 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
402 make_bad_inode(inode);
403 err = -EIO;
404 } else {
405 struct fuse_inode *fi = get_fuse_inode(inode);
406 fuse_change_attributes(inode, &arg.attr);
407 fi->i_time = time_to_jiffies(arg.attr_valid,
408 arg.attr_valid_nsec);
409 }
410 }
411 return err;
412}
413
87729a55
MS
414/*
415 * Calling into a user-controlled filesystem gives the filesystem
416 * daemon ptrace-like capabilities over the requester process. This
417 * means, that the filesystem daemon is able to record the exact
418 * filesystem operations performed, and can also control the behavior
419 * of the requester process in otherwise impossible ways. For example
420 * it can delay the operation for arbitrary length of time allowing
421 * DoS against the requester.
422 *
423 * For this reason only those processes can call into the filesystem,
424 * for which the owner of the mount has ptrace privilege. This
425 * excludes processes started by other users, suid or sgid processes.
426 */
427static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
428{
429 if (fc->flags & FUSE_ALLOW_OTHER)
430 return 1;
431
432 if (task->euid == fc->user_id &&
433 task->suid == fc->user_id &&
434 task->uid == fc->user_id &&
435 task->egid == fc->group_id &&
436 task->sgid == fc->group_id &&
437 task->gid == fc->group_id)
438 return 1;
439
440 return 0;
441}
442
e5e5558e
MS
443static int fuse_revalidate(struct dentry *entry)
444{
445 struct inode *inode = entry->d_inode;
446 struct fuse_inode *fi = get_fuse_inode(inode);
447 struct fuse_conn *fc = get_fuse_conn(inode);
448
87729a55
MS
449 if (!fuse_allow_task(fc, current))
450 return -EACCES;
451 if (get_node_id(inode) != FUSE_ROOT_ID &&
452 time_before_eq(jiffies, fi->i_time))
e5e5558e
MS
453 return 0;
454
455 return fuse_do_getattr(inode);
456}
457
458static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
459{
460 struct fuse_conn *fc = get_fuse_conn(inode);
461
87729a55 462 if (!fuse_allow_task(fc, current))
e5e5558e 463 return -EACCES;
1e9a4ed9
MS
464 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
465 int err = generic_permission(inode, mask, NULL);
466
467 /* If permission is denied, try to refresh file
468 attributes. This is also needed, because the root
469 node will at first have no permissions */
470 if (err == -EACCES) {
471 err = fuse_do_getattr(inode);
472 if (!err)
473 err = generic_permission(inode, mask, NULL);
474 }
475
476 /* FIXME: Need some mechanism to revoke permissions:
477 currently if the filesystem suddenly changes the
478 file mode, we will not be informed about it, and
479 continue to allow access to the file/directory.
480
481 This is actually not so grave, since the user can
482 simply keep access to the file/directory anyway by
483 keeping it open... */
484
485 return err;
486 } else {
e5e5558e
MS
487 int mode = inode->i_mode;
488 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
489 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
490 return -EROFS;
491 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
492 return -EACCES;
493 return 0;
494 }
495}
496
497static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
498 void *dstbuf, filldir_t filldir)
499{
500 while (nbytes >= FUSE_NAME_OFFSET) {
501 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
502 size_t reclen = FUSE_DIRENT_SIZE(dirent);
503 int over;
504 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
505 return -EIO;
506 if (reclen > nbytes)
507 break;
508
509 over = filldir(dstbuf, dirent->name, dirent->namelen,
510 file->f_pos, dirent->ino, dirent->type);
511 if (over)
512 break;
513
514 buf += reclen;
515 nbytes -= reclen;
516 file->f_pos = dirent->off;
517 }
518
519 return 0;
520}
521
04730fef
MS
522static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
523 struct inode *inode, loff_t pos,
524 size_t count)
e5e5558e 525{
04730fef 526 return fuse_send_read_common(req, file, inode, pos, count, 1);
e5e5558e
MS
527}
528
04730fef 529static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
e5e5558e 530{
04730fef
MS
531 int err;
532 size_t nbytes;
533 struct page *page;
e5e5558e
MS
534 struct inode *inode = file->f_dentry->d_inode;
535 struct fuse_conn *fc = get_fuse_conn(inode);
04730fef 536 struct fuse_req *req = fuse_get_request_nonint(fc);
e5e5558e 537 if (!req)
04730fef 538 return -EINTR;
e5e5558e 539
04730fef
MS
540 page = alloc_page(GFP_KERNEL);
541 if (!page) {
542 fuse_put_request(fc, req);
543 return -ENOMEM;
544 }
545 req->num_pages = 1;
546 req->pages[0] = page;
547 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
e5e5558e
MS
548 err = req->out.h.error;
549 fuse_put_request(fc, req);
550 if (!err)
04730fef
MS
551 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
552 filldir);
e5e5558e 553
04730fef
MS
554 __free_page(page);
555 return err;
e5e5558e
MS
556}
557
558static char *read_link(struct dentry *dentry)
559{
560 struct inode *inode = dentry->d_inode;
561 struct fuse_conn *fc = get_fuse_conn(inode);
562 struct fuse_req *req = fuse_get_request(fc);
563 char *link;
564
565 if (!req)
566 return ERR_PTR(-ERESTARTNOINTR);
567
568 link = (char *) __get_free_page(GFP_KERNEL);
569 if (!link) {
570 link = ERR_PTR(-ENOMEM);
571 goto out;
572 }
573 req->in.h.opcode = FUSE_READLINK;
574 req->in.h.nodeid = get_node_id(inode);
575 req->inode = inode;
576 req->out.argvar = 1;
577 req->out.numargs = 1;
578 req->out.args[0].size = PAGE_SIZE - 1;
579 req->out.args[0].value = link;
580 request_send(fc, req);
581 if (req->out.h.error) {
582 free_page((unsigned long) link);
583 link = ERR_PTR(req->out.h.error);
584 } else
585 link[req->out.args[0].size] = '\0';
586 out:
587 fuse_put_request(fc, req);
588 return link;
589}
590
591static void free_link(char *link)
592{
593 if (!IS_ERR(link))
594 free_page((unsigned long) link);
595}
596
597static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
598{
599 nd_set_link(nd, read_link(dentry));
600 return NULL;
601}
602
603static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
604{
605 free_link(nd_get_link(nd));
606}
607
608static int fuse_dir_open(struct inode *inode, struct file *file)
609{
04730fef 610 return fuse_open_common(inode, file, 1);
e5e5558e
MS
611}
612
613static int fuse_dir_release(struct inode *inode, struct file *file)
614{
04730fef 615 return fuse_release_common(inode, file, 1);
e5e5558e
MS
616}
617
9e6268db
MS
618static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
619{
620 unsigned ivalid = iattr->ia_valid;
621 unsigned fvalid = 0;
622
623 memset(fattr, 0, sizeof(*fattr));
624
625 if (ivalid & ATTR_MODE)
626 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
627 if (ivalid & ATTR_UID)
628 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
629 if (ivalid & ATTR_GID)
630 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
631 if (ivalid & ATTR_SIZE)
632 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
633 /* You can only _set_ these together (they may change by themselves) */
634 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
635 fvalid |= FATTR_ATIME | FATTR_MTIME;
636 fattr->atime = iattr->ia_atime.tv_sec;
637 fattr->mtime = iattr->ia_mtime.tv_sec;
638 }
639
640 return fvalid;
641}
642
643static int fuse_setattr(struct dentry *entry, struct iattr *attr)
644{
645 struct inode *inode = entry->d_inode;
646 struct fuse_conn *fc = get_fuse_conn(inode);
647 struct fuse_inode *fi = get_fuse_inode(inode);
648 struct fuse_req *req;
649 struct fuse_setattr_in inarg;
650 struct fuse_attr_out outarg;
651 int err;
652 int is_truncate = 0;
653
1e9a4ed9
MS
654 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
655 err = inode_change_ok(inode, attr);
656 if (err)
657 return err;
658 }
659
9e6268db
MS
660 if (attr->ia_valid & ATTR_SIZE) {
661 unsigned long limit;
662 is_truncate = 1;
663 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
664 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
665 send_sig(SIGXFSZ, current, 0);
666 return -EFBIG;
667 }
668 }
669
670 req = fuse_get_request(fc);
671 if (!req)
672 return -ERESTARTNOINTR;
673
674 memset(&inarg, 0, sizeof(inarg));
675 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
676 req->in.h.opcode = FUSE_SETATTR;
677 req->in.h.nodeid = get_node_id(inode);
678 req->inode = inode;
679 req->in.numargs = 1;
680 req->in.args[0].size = sizeof(inarg);
681 req->in.args[0].value = &inarg;
682 req->out.numargs = 1;
683 req->out.args[0].size = sizeof(outarg);
684 req->out.args[0].value = &outarg;
685 request_send(fc, req);
686 err = req->out.h.error;
687 fuse_put_request(fc, req);
688 if (!err) {
689 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
690 make_bad_inode(inode);
691 err = -EIO;
692 } else {
693 if (is_truncate) {
694 loff_t origsize = i_size_read(inode);
695 i_size_write(inode, outarg.attr.size);
696 if (origsize > outarg.attr.size)
697 vmtruncate(inode, outarg.attr.size);
698 }
699 fuse_change_attributes(inode, &outarg.attr);
700 fi->i_time = time_to_jiffies(outarg.attr_valid,
701 outarg.attr_valid_nsec);
702 }
703 } else if (err == -EINTR)
704 fuse_invalidate_attr(inode);
705
706 return err;
707}
708
e5e5558e
MS
709static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
710 struct kstat *stat)
711{
712 struct inode *inode = entry->d_inode;
713 int err = fuse_revalidate(entry);
714 if (!err)
715 generic_fillattr(inode, stat);
716
717 return err;
718}
719
720static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
721 struct nameidata *nd)
722{
723 struct inode *inode;
724 int err = fuse_lookup_iget(dir, entry, &inode);
725 if (err)
726 return ERR_PTR(err);
727 if (inode && S_ISDIR(inode->i_mode)) {
728 /* Don't allow creating an alias to a directory */
729 struct dentry *alias = d_find_alias(inode);
730 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
731 dput(alias);
732 iput(inode);
733 return ERR_PTR(-EIO);
734 }
735 }
736 return d_splice_alias(inode, entry);
737}
738
92a8780e
MS
739static int fuse_setxattr(struct dentry *entry, const char *name,
740 const void *value, size_t size, int flags)
741{
742 struct inode *inode = entry->d_inode;
743 struct fuse_conn *fc = get_fuse_conn(inode);
744 struct fuse_req *req;
745 struct fuse_setxattr_in inarg;
746 int err;
747
748 if (size > FUSE_XATTR_SIZE_MAX)
749 return -E2BIG;
750
751 if (fc->no_setxattr)
752 return -EOPNOTSUPP;
753
754 req = fuse_get_request(fc);
755 if (!req)
756 return -ERESTARTNOINTR;
757
758 memset(&inarg, 0, sizeof(inarg));
759 inarg.size = size;
760 inarg.flags = flags;
761 req->in.h.opcode = FUSE_SETXATTR;
762 req->in.h.nodeid = get_node_id(inode);
763 req->inode = inode;
764 req->in.numargs = 3;
765 req->in.args[0].size = sizeof(inarg);
766 req->in.args[0].value = &inarg;
767 req->in.args[1].size = strlen(name) + 1;
768 req->in.args[1].value = name;
769 req->in.args[2].size = size;
770 req->in.args[2].value = value;
771 request_send(fc, req);
772 err = req->out.h.error;
773 fuse_put_request(fc, req);
774 if (err == -ENOSYS) {
775 fc->no_setxattr = 1;
776 err = -EOPNOTSUPP;
777 }
778 return err;
779}
780
781static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
782 void *value, size_t size)
783{
784 struct inode *inode = entry->d_inode;
785 struct fuse_conn *fc = get_fuse_conn(inode);
786 struct fuse_req *req;
787 struct fuse_getxattr_in inarg;
788 struct fuse_getxattr_out outarg;
789 ssize_t ret;
790
791 if (fc->no_getxattr)
792 return -EOPNOTSUPP;
793
794 req = fuse_get_request(fc);
795 if (!req)
796 return -ERESTARTNOINTR;
797
798 memset(&inarg, 0, sizeof(inarg));
799 inarg.size = size;
800 req->in.h.opcode = FUSE_GETXATTR;
801 req->in.h.nodeid = get_node_id(inode);
802 req->inode = inode;
803 req->in.numargs = 2;
804 req->in.args[0].size = sizeof(inarg);
805 req->in.args[0].value = &inarg;
806 req->in.args[1].size = strlen(name) + 1;
807 req->in.args[1].value = name;
808 /* This is really two different operations rolled into one */
809 req->out.numargs = 1;
810 if (size) {
811 req->out.argvar = 1;
812 req->out.args[0].size = size;
813 req->out.args[0].value = value;
814 } else {
815 req->out.args[0].size = sizeof(outarg);
816 req->out.args[0].value = &outarg;
817 }
818 request_send(fc, req);
819 ret = req->out.h.error;
820 if (!ret)
821 ret = size ? req->out.args[0].size : outarg.size;
822 else {
823 if (ret == -ENOSYS) {
824 fc->no_getxattr = 1;
825 ret = -EOPNOTSUPP;
826 }
827 }
828 fuse_put_request(fc, req);
829 return ret;
830}
831
832static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
833{
834 struct inode *inode = entry->d_inode;
835 struct fuse_conn *fc = get_fuse_conn(inode);
836 struct fuse_req *req;
837 struct fuse_getxattr_in inarg;
838 struct fuse_getxattr_out outarg;
839 ssize_t ret;
840
841 if (fc->no_listxattr)
842 return -EOPNOTSUPP;
843
844 req = fuse_get_request(fc);
845 if (!req)
846 return -ERESTARTNOINTR;
847
848 memset(&inarg, 0, sizeof(inarg));
849 inarg.size = size;
850 req->in.h.opcode = FUSE_LISTXATTR;
851 req->in.h.nodeid = get_node_id(inode);
852 req->inode = inode;
853 req->in.numargs = 1;
854 req->in.args[0].size = sizeof(inarg);
855 req->in.args[0].value = &inarg;
856 /* This is really two different operations rolled into one */
857 req->out.numargs = 1;
858 if (size) {
859 req->out.argvar = 1;
860 req->out.args[0].size = size;
861 req->out.args[0].value = list;
862 } else {
863 req->out.args[0].size = sizeof(outarg);
864 req->out.args[0].value = &outarg;
865 }
866 request_send(fc, req);
867 ret = req->out.h.error;
868 if (!ret)
869 ret = size ? req->out.args[0].size : outarg.size;
870 else {
871 if (ret == -ENOSYS) {
872 fc->no_listxattr = 1;
873 ret = -EOPNOTSUPP;
874 }
875 }
876 fuse_put_request(fc, req);
877 return ret;
878}
879
880static int fuse_removexattr(struct dentry *entry, const char *name)
881{
882 struct inode *inode = entry->d_inode;
883 struct fuse_conn *fc = get_fuse_conn(inode);
884 struct fuse_req *req;
885 int err;
886
887 if (fc->no_removexattr)
888 return -EOPNOTSUPP;
889
890 req = fuse_get_request(fc);
891 if (!req)
892 return -ERESTARTNOINTR;
893
894 req->in.h.opcode = FUSE_REMOVEXATTR;
895 req->in.h.nodeid = get_node_id(inode);
896 req->inode = inode;
897 req->in.numargs = 1;
898 req->in.args[0].size = strlen(name) + 1;
899 req->in.args[0].value = name;
900 request_send(fc, req);
901 err = req->out.h.error;
902 fuse_put_request(fc, req);
903 if (err == -ENOSYS) {
904 fc->no_removexattr = 1;
905 err = -EOPNOTSUPP;
906 }
907 return err;
908}
909
e5e5558e
MS
910static struct inode_operations fuse_dir_inode_operations = {
911 .lookup = fuse_lookup,
9e6268db
MS
912 .mkdir = fuse_mkdir,
913 .symlink = fuse_symlink,
914 .unlink = fuse_unlink,
915 .rmdir = fuse_rmdir,
916 .rename = fuse_rename,
917 .link = fuse_link,
918 .setattr = fuse_setattr,
919 .create = fuse_create,
920 .mknod = fuse_mknod,
e5e5558e
MS
921 .permission = fuse_permission,
922 .getattr = fuse_getattr,
92a8780e
MS
923 .setxattr = fuse_setxattr,
924 .getxattr = fuse_getxattr,
925 .listxattr = fuse_listxattr,
926 .removexattr = fuse_removexattr,
e5e5558e
MS
927};
928
929static struct file_operations fuse_dir_operations = {
b6aeaded 930 .llseek = generic_file_llseek,
e5e5558e
MS
931 .read = generic_read_dir,
932 .readdir = fuse_readdir,
933 .open = fuse_dir_open,
934 .release = fuse_dir_release,
935};
936
937static struct inode_operations fuse_common_inode_operations = {
9e6268db 938 .setattr = fuse_setattr,
e5e5558e
MS
939 .permission = fuse_permission,
940 .getattr = fuse_getattr,
92a8780e
MS
941 .setxattr = fuse_setxattr,
942 .getxattr = fuse_getxattr,
943 .listxattr = fuse_listxattr,
944 .removexattr = fuse_removexattr,
e5e5558e
MS
945};
946
947static struct inode_operations fuse_symlink_inode_operations = {
9e6268db 948 .setattr = fuse_setattr,
e5e5558e
MS
949 .follow_link = fuse_follow_link,
950 .put_link = fuse_put_link,
951 .readlink = generic_readlink,
952 .getattr = fuse_getattr,
92a8780e
MS
953 .setxattr = fuse_setxattr,
954 .getxattr = fuse_getxattr,
955 .listxattr = fuse_listxattr,
956 .removexattr = fuse_removexattr,
e5e5558e
MS
957};
958
959void fuse_init_common(struct inode *inode)
960{
961 inode->i_op = &fuse_common_inode_operations;
962}
963
964void fuse_init_dir(struct inode *inode)
965{
966 inode->i_op = &fuse_dir_inode_operations;
967 inode->i_fop = &fuse_dir_operations;
968}
969
970void fuse_init_symlink(struct inode *inode)
971{
972 inode->i_op = &fuse_symlink_inode_operations;
973}
This page took 0.066078 seconds and 5 git commands to generate.