aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r--fs/fuse/dir.c172
1 files changed, 154 insertions, 18 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 70dba721acab..c045cc70c749 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -13,6 +13,7 @@
13#include <linux/gfp.h> 13#include <linux/gfp.h>
14#include <linux/sched.h> 14#include <linux/sched.h>
15#include <linux/namei.h> 15#include <linux/namei.h>
16#include <linux/mount.h>
16 17
17static inline unsigned long time_to_jiffies(unsigned long sec, 18static inline unsigned long time_to_jiffies(unsigned long sec,
18 unsigned long nsec) 19 unsigned long nsec)
@@ -134,6 +135,101 @@ static void fuse_invalidate_entry(struct dentry *entry)
134 entry->d_time = jiffies - 1; 135 entry->d_time = jiffies - 1;
135} 136}
136 137
138static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
139 struct nameidata *nd)
140{
141 int err;
142 struct inode *inode;
143 struct fuse_conn *fc = get_fuse_conn(dir);
144 struct fuse_req *req;
145 struct fuse_open_in inarg;
146 struct fuse_open_out outopen;
147 struct fuse_entry_out outentry;
148 struct fuse_inode *fi;
149 struct fuse_file *ff;
150 struct file *file;
151 int flags = nd->intent.open.flags - 1;
152
153 err = -ENOSYS;
154 if (fc->no_create)
155 goto out;
156
157 err = -ENAMETOOLONG;
158 if (entry->d_name.len > FUSE_NAME_MAX)
159 goto out;
160
161 err = -EINTR;
162 req = fuse_get_request(fc);
163 if (!req)
164 goto out;
165
166 ff = fuse_file_alloc();
167 if (!ff)
168 goto out_put_request;
169
170 flags &= ~O_NOCTTY;
171 memset(&inarg, 0, sizeof(inarg));
172 inarg.flags = flags;
173 inarg.mode = mode;
174 req->in.h.opcode = FUSE_CREATE;
175 req->in.h.nodeid = get_node_id(dir);
176 req->inode = dir;
177 req->in.numargs = 2;
178 req->in.args[0].size = sizeof(inarg);
179 req->in.args[0].value = &inarg;
180 req->in.args[1].size = entry->d_name.len + 1;
181 req->in.args[1].value = entry->d_name.name;
182 req->out.numargs = 2;
183 req->out.args[0].size = sizeof(outentry);
184 req->out.args[0].value = &outentry;
185 req->out.args[1].size = sizeof(outopen);
186 req->out.args[1].value = &outopen;
187 request_send(fc, req);
188 err = req->out.h.error;
189 if (err) {
190 if (err == -ENOSYS)
191 fc->no_create = 1;
192 goto out_free_ff;
193 }
194
195 err = -EIO;
196 if (!S_ISREG(outentry.attr.mode))
197 goto out_free_ff;
198
199 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
200 &outentry.attr);
201 err = -ENOMEM;
202 if (!inode) {
203 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
204 ff->fh = outopen.fh;
205 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
206 goto out_put_request;
207 }
208 fuse_put_request(fc, req);
209 entry->d_time = time_to_jiffies(outentry.entry_valid,
210 outentry.entry_valid_nsec);
211 fi = get_fuse_inode(inode);
212 fi->i_time = time_to_jiffies(outentry.attr_valid,
213 outentry.attr_valid_nsec);
214
215 d_instantiate(entry, inode);
216 file = lookup_instantiate_filp(nd, entry, generic_file_open);
217 if (IS_ERR(file)) {
218 ff->fh = outopen.fh;
219 fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
220 return PTR_ERR(file);
221 }
222 fuse_finish_open(inode, file, ff, &outopen);
223 return 0;
224
225 out_free_ff:
226 fuse_file_free(ff);
227 out_put_request:
228 fuse_put_request(fc, req);
229 out:
230 return err;
231}
232
137static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 233static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
138 struct inode *dir, struct dentry *entry, 234 struct inode *dir, struct dentry *entry,
139 int mode) 235 int mode)
@@ -208,6 +304,12 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
208static int fuse_create(struct inode *dir, struct dentry *entry, int mode, 304static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
209 struct nameidata *nd) 305 struct nameidata *nd)
210{ 306{
307 if (nd && (nd->flags & LOOKUP_CREATE)) {
308 int err = fuse_create_open(dir, entry, mode, nd);
309 if (err != -ENOSYS)
310 return err;
311 /* Fall back on mknod */
312 }
211 return fuse_mknod(dir, entry, mode, 0); 313 return fuse_mknod(dir, entry, mode, 0);
212} 314}
213 315
@@ -461,6 +563,38 @@ static int fuse_revalidate(struct dentry *entry)
461 return fuse_do_getattr(inode); 563 return fuse_do_getattr(inode);
462} 564}
463 565
566static int fuse_access(struct inode *inode, int mask)
567{
568 struct fuse_conn *fc = get_fuse_conn(inode);
569 struct fuse_req *req;
570 struct fuse_access_in inarg;
571 int err;
572
573 if (fc->no_access)
574 return 0;
575
576 req = fuse_get_request(fc);
577 if (!req)
578 return -EINTR;
579
580 memset(&inarg, 0, sizeof(inarg));
581 inarg.mask = mask;
582 req->in.h.opcode = FUSE_ACCESS;
583 req->in.h.nodeid = get_node_id(inode);
584 req->inode = inode;
585 req->in.numargs = 1;
586 req->in.args[0].size = sizeof(inarg);
587 req->in.args[0].value = &inarg;
588 request_send(fc, req);
589 err = req->out.h.error;
590 fuse_put_request(fc, req);
591 if (err == -ENOSYS) {
592 fc->no_access = 1;
593 err = 0;
594 }
595 return err;
596}
597
464static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 598static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
465{ 599{
466 struct fuse_conn *fc = get_fuse_conn(inode); 600 struct fuse_conn *fc = get_fuse_conn(inode);
@@ -491,11 +625,11 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
491 return err; 625 return err;
492 } else { 626 } else {
493 int mode = inode->i_mode; 627 int mode = inode->i_mode;
494 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
495 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
496 return -EROFS;
497 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) 628 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
498 return -EACCES; 629 return -EACCES;
630
631 if (nd && (nd->flags & LOOKUP_ACCESS))
632 return fuse_access(inode, mask);
499 return 0; 633 return 0;
500 } 634 }
501} 635}
@@ -629,29 +763,29 @@ static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
629 return file ? fuse_fsync_common(file, de, datasync, 1) : 0; 763 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
630} 764}
631 765
632static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) 766static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
633{ 767{
634 unsigned ivalid = iattr->ia_valid; 768 unsigned ivalid = iattr->ia_valid;
635 unsigned fvalid = 0;
636
637 memset(fattr, 0, sizeof(*fattr));
638 769
639 if (ivalid & ATTR_MODE) 770 if (ivalid & ATTR_MODE)
640 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode; 771 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
641 if (ivalid & ATTR_UID) 772 if (ivalid & ATTR_UID)
642 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid; 773 arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
643 if (ivalid & ATTR_GID) 774 if (ivalid & ATTR_GID)
644 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid; 775 arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
645 if (ivalid & ATTR_SIZE) 776 if (ivalid & ATTR_SIZE)
646 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size; 777 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
647 /* You can only _set_ these together (they may change by themselves) */ 778 /* You can only _set_ these together (they may change by themselves) */
648 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { 779 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
649 fvalid |= FATTR_ATIME | FATTR_MTIME; 780 arg->valid |= FATTR_ATIME | FATTR_MTIME;
650 fattr->atime = iattr->ia_atime.tv_sec; 781 arg->atime = iattr->ia_atime.tv_sec;
651 fattr->mtime = iattr->ia_mtime.tv_sec; 782 arg->mtime = iattr->ia_mtime.tv_sec;
783 }
784 if (ivalid & ATTR_FILE) {
785 struct fuse_file *ff = iattr->ia_file->private_data;
786 arg->valid |= FATTR_FH;
787 arg->fh = ff->fh;
652 } 788 }
653
654 return fvalid;
655} 789}
656 790
657static int fuse_setattr(struct dentry *entry, struct iattr *attr) 791static int fuse_setattr(struct dentry *entry, struct iattr *attr)
@@ -686,7 +820,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
686 return -EINTR; 820 return -EINTR;
687 821
688 memset(&inarg, 0, sizeof(inarg)); 822 memset(&inarg, 0, sizeof(inarg));
689 inarg.valid = iattr_to_fattr(attr, &inarg.attr); 823 iattr_to_fattr(attr, &inarg);
690 req->in.h.opcode = FUSE_SETATTR; 824 req->in.h.opcode = FUSE_SETATTR;
691 req->in.h.nodeid = get_node_id(inode); 825 req->in.h.nodeid = get_node_id(inode);
692 req->inode = inode; 826 req->inode = inode;
@@ -735,7 +869,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
735 struct nameidata *nd) 869 struct nameidata *nd)
736{ 870{
737 struct inode *inode; 871 struct inode *inode;
738 int err = fuse_lookup_iget(dir, entry, &inode); 872 int err;
873
874 err = fuse_lookup_iget(dir, entry, &inode);
739 if (err) 875 if (err)
740 return ERR_PTR(err); 876 return ERR_PTR(err);
741 if (inode && S_ISDIR(inode->i_mode)) { 877 if (inode && S_ISDIR(inode->i_mode)) {