aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/dir.c373
-rw-r--r--fs/fuse/fuse_i.h7
-rw-r--r--fs/fuse/inode.c15
-rw-r--r--include/linux/fuse.h43
4 files changed, 419 insertions, 19 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index a89730e70c58..92c7188ccd16 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -42,7 +42,6 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
42 return 0; 42 return 0;
43 else if (time_after(jiffies, entry->d_time)) { 43 else if (time_after(jiffies, entry->d_time)) {
44 int err; 44 int err;
45 int version;
46 struct fuse_entry_out outarg; 45 struct fuse_entry_out outarg;
47 struct inode *inode = entry->d_inode; 46 struct inode *inode = entry->d_inode;
48 struct fuse_inode *fi = get_fuse_inode(inode); 47 struct fuse_inode *fi = get_fuse_inode(inode);
@@ -53,15 +52,19 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
53 52
54 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); 53 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
55 request_send_nonint(fc, req); 54 request_send_nonint(fc, req);
56 version = req->out.h.unique;
57 err = req->out.h.error; 55 err = req->out.h.error;
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 }
58 fuse_put_request(fc, req); 63 fuse_put_request(fc, req);
59 if (err || outarg.nodeid != get_node_id(inode) || 64 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
60 (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
61 return 0; 65 return 0;
62 66
63 fuse_change_attributes(inode, &outarg.attr); 67 fuse_change_attributes(inode, &outarg.attr);
64 inode->i_version = version;
65 entry->d_time = time_to_jiffies(outarg.entry_valid, 68 entry->d_time = time_to_jiffies(outarg.entry_valid,
66 outarg.entry_valid_nsec); 69 outarg.entry_valid_nsec);
67 fi->i_time = time_to_jiffies(outarg.attr_valid, 70 fi->i_time = time_to_jiffies(outarg.attr_valid,
@@ -78,7 +81,6 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
78 struct inode **inodep) 81 struct inode **inodep)
79{ 82{
80 int err; 83 int err;
81 int version;
82 struct fuse_entry_out outarg; 84 struct fuse_entry_out outarg;
83 struct inode *inode = NULL; 85 struct inode *inode = NULL;
84 struct fuse_conn *fc = get_fuse_conn(dir); 86 struct fuse_conn *fc = get_fuse_conn(dir);
@@ -93,13 +95,12 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
93 95
94 fuse_lookup_init(req, dir, entry, &outarg); 96 fuse_lookup_init(req, dir, entry, &outarg);
95 request_send(fc, req); 97 request_send(fc, req);
96 version = req->out.h.unique;
97 err = req->out.h.error; 98 err = req->out.h.error;
98 if (!err) { 99 if (!err) {
99 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 100 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
100 &outarg.attr, version); 101 &outarg.attr);
101 if (!inode) { 102 if (!inode) {
102 fuse_send_forget(fc, req, outarg.nodeid, version); 103 fuse_send_forget(fc, req, outarg.nodeid, 1);
103 return -ENOMEM; 104 return -ENOMEM;
104 } 105 }
105 } 106 }
@@ -120,6 +121,264 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
120 return 0; 121 return 0;
121} 122}
122 123
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
123int fuse_do_getattr(struct inode *inode) 382int fuse_do_getattr(struct inode *inode)
124{ 383{
125 int err; 384 int err;
@@ -341,6 +600,91 @@ static int fuse_dir_release(struct inode *inode, struct file *file)
341 return 0; 600 return 0;
342} 601}
343 602
603static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
604{
605 unsigned ivalid = iattr->ia_valid;
606 unsigned fvalid = 0;
607
608 memset(fattr, 0, sizeof(*fattr));
609
610 if (ivalid & ATTR_MODE)
611 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
612 if (ivalid & ATTR_UID)
613 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
614 if (ivalid & ATTR_GID)
615 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
616 if (ivalid & ATTR_SIZE)
617 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
618 /* You can only _set_ these together (they may change by themselves) */
619 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
620 fvalid |= FATTR_ATIME | FATTR_MTIME;
621 fattr->atime = iattr->ia_atime.tv_sec;
622 fattr->mtime = iattr->ia_mtime.tv_sec;
623 }
624
625 return fvalid;
626}
627
628static int fuse_setattr(struct dentry *entry, struct iattr *attr)
629{
630 struct inode *inode = entry->d_inode;
631 struct fuse_conn *fc = get_fuse_conn(inode);
632 struct fuse_inode *fi = get_fuse_inode(inode);
633 struct fuse_req *req;
634 struct fuse_setattr_in inarg;
635 struct fuse_attr_out outarg;
636 int err;
637 int is_truncate = 0;
638
639 if (attr->ia_valid & ATTR_SIZE) {
640 unsigned long limit;
641 is_truncate = 1;
642 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
643 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
644 send_sig(SIGXFSZ, current, 0);
645 return -EFBIG;
646 }
647 }
648
649 req = fuse_get_request(fc);
650 if (!req)
651 return -ERESTARTNOINTR;
652
653 memset(&inarg, 0, sizeof(inarg));
654 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
655 req->in.h.opcode = FUSE_SETATTR;
656 req->in.h.nodeid = get_node_id(inode);
657 req->inode = inode;
658 req->in.numargs = 1;
659 req->in.args[0].size = sizeof(inarg);
660 req->in.args[0].value = &inarg;
661 req->out.numargs = 1;
662 req->out.args[0].size = sizeof(outarg);
663 req->out.args[0].value = &outarg;
664 request_send(fc, req);
665 err = req->out.h.error;
666 fuse_put_request(fc, req);
667 if (!err) {
668 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
669 make_bad_inode(inode);
670 err = -EIO;
671 } else {
672 if (is_truncate) {
673 loff_t origsize = i_size_read(inode);
674 i_size_write(inode, outarg.attr.size);
675 if (origsize > outarg.attr.size)
676 vmtruncate(inode, outarg.attr.size);
677 }
678 fuse_change_attributes(inode, &outarg.attr);
679 fi->i_time = time_to_jiffies(outarg.attr_valid,
680 outarg.attr_valid_nsec);
681 }
682 } else if (err == -EINTR)
683 fuse_invalidate_attr(inode);
684
685 return err;
686}
687
344static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, 688static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
345 struct kstat *stat) 689 struct kstat *stat)
346{ 690{
@@ -373,6 +717,15 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
373 717
374static struct inode_operations fuse_dir_inode_operations = { 718static struct inode_operations fuse_dir_inode_operations = {
375 .lookup = fuse_lookup, 719 .lookup = fuse_lookup,
720 .mkdir = fuse_mkdir,
721 .symlink = fuse_symlink,
722 .unlink = fuse_unlink,
723 .rmdir = fuse_rmdir,
724 .rename = fuse_rename,
725 .link = fuse_link,
726 .setattr = fuse_setattr,
727 .create = fuse_create,
728 .mknod = fuse_mknod,
376 .permission = fuse_permission, 729 .permission = fuse_permission,
377 .getattr = fuse_getattr, 730 .getattr = fuse_getattr,
378}; 731};
@@ -385,11 +738,13 @@ static struct file_operations fuse_dir_operations = {
385}; 738};
386 739
387static struct inode_operations fuse_common_inode_operations = { 740static struct inode_operations fuse_common_inode_operations = {
741 .setattr = fuse_setattr,
388 .permission = fuse_permission, 742 .permission = fuse_permission,
389 .getattr = fuse_getattr, 743 .getattr = fuse_getattr,
390}; 744};
391 745
392static struct inode_operations fuse_symlink_inode_operations = { 746static struct inode_operations fuse_symlink_inode_operations = {
747 .setattr = fuse_setattr,
393 .follow_link = fuse_follow_link, 748 .follow_link = fuse_follow_link,
394 .put_link = fuse_put_link, 749 .put_link = fuse_put_link,
395 .readlink = generic_readlink, 750 .readlink = generic_readlink,
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 8d91e1492f96..87d25b8f2dc1 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -30,6 +30,9 @@ struct fuse_inode {
30 * and kernel */ 30 * and kernel */
31 u64 nodeid; 31 u64 nodeid;
32 32
33 /** Number of lookups on this inode */
34 u64 nlookup;
35
33 /** The request used for sending the FORGET message */ 36 /** The request used for sending the FORGET message */
34 struct fuse_req *forget_req; 37 struct fuse_req *forget_req;
35 38
@@ -252,13 +255,13 @@ extern spinlock_t fuse_lock;
252 * Get a filled in inode 255 * Get a filled in inode
253 */ 256 */
254struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, 257struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
255 int generation, struct fuse_attr *attr, int version); 258 int generation, struct fuse_attr *attr);
256 259
257/** 260/**
258 * Send FORGET command 261 * Send FORGET command
259 */ 262 */
260void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, 263void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
261 unsigned long nodeid, int version); 264 unsigned long nodeid, u64 nlookup);
262 265
263/** 266/**
264 * Initialise inode operations on regular files and special files 267 * Initialise inode operations on regular files and special files
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 41498a1952a0..fa03f80806e5 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -51,6 +51,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
51 fi = get_fuse_inode(inode); 51 fi = get_fuse_inode(inode);
52 fi->i_time = jiffies - 1; 52 fi->i_time = jiffies - 1;
53 fi->nodeid = 0; 53 fi->nodeid = 0;
54 fi->nlookup = 0;
54 fi->forget_req = fuse_request_alloc(); 55 fi->forget_req = fuse_request_alloc();
55 if (!fi->forget_req) { 56 if (!fi->forget_req) {
56 kmem_cache_free(fuse_inode_cachep, inode); 57 kmem_cache_free(fuse_inode_cachep, inode);
@@ -74,10 +75,10 @@ static void fuse_read_inode(struct inode *inode)
74} 75}
75 76
76void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, 77void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
77 unsigned long nodeid, int version) 78 unsigned long nodeid, u64 nlookup)
78{ 79{
79 struct fuse_forget_in *inarg = &req->misc.forget_in; 80 struct fuse_forget_in *inarg = &req->misc.forget_in;
80 inarg->version = version; 81 inarg->nlookup = nlookup;
81 req->in.h.opcode = FUSE_FORGET; 82 req->in.h.opcode = FUSE_FORGET;
82 req->in.h.nodeid = nodeid; 83 req->in.h.nodeid = nodeid;
83 req->in.numargs = 1; 84 req->in.numargs = 1;
@@ -91,7 +92,7 @@ static void fuse_clear_inode(struct inode *inode)
91 struct fuse_conn *fc = get_fuse_conn(inode); 92 struct fuse_conn *fc = get_fuse_conn(inode);
92 if (fc) { 93 if (fc) {
93 struct fuse_inode *fi = get_fuse_inode(inode); 94 struct fuse_inode *fi = get_fuse_inode(inode);
94 fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version); 95 fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup);
95 fi->forget_req = NULL; 96 fi->forget_req = NULL;
96 } 97 }
97} 98}
@@ -156,9 +157,10 @@ static int fuse_inode_set(struct inode *inode, void *_nodeidp)
156} 157}
157 158
158struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, 159struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
159 int generation, struct fuse_attr *attr, int version) 160 int generation, struct fuse_attr *attr)
160{ 161{
161 struct inode *inode; 162 struct inode *inode;
163 struct fuse_inode *fi;
162 struct fuse_conn *fc = get_fuse_conn_super(sb); 164 struct fuse_conn *fc = get_fuse_conn_super(sb);
163 int retried = 0; 165 int retried = 0;
164 166
@@ -181,8 +183,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
181 goto retry; 183 goto retry;
182 } 184 }
183 185
186 fi = get_fuse_inode(inode);
187 fi->nlookup ++;
184 fuse_change_attributes(inode, attr); 188 fuse_change_attributes(inode, attr);
185 inode->i_version = version;
186 return inode; 189 return inode;
187} 190}
188 191
@@ -389,7 +392,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
389 392
390 attr.mode = mode; 393 attr.mode = mode;
391 attr.ino = FUSE_ROOT_ID; 394 attr.ino = FUSE_ROOT_ID;
392 return fuse_iget(sb, 1, 0, &attr, 0); 395 return fuse_iget(sb, 1, 0, &attr);
393} 396}
394 397
395static struct super_operations fuse_super_operations = { 398static struct super_operations fuse_super_operations = {
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 21b9ba16f8d5..19d69a3e1623 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -11,7 +11,7 @@
11#include <asm/types.h> 11#include <asm/types.h>
12 12
13/** Version number of this interface */ 13/** Version number of this interface */
14#define FUSE_KERNEL_VERSION 6 14#define FUSE_KERNEL_VERSION 7
15 15
16/** Minor version number of this interface */ 16/** Minor version number of this interface */
17#define FUSE_KERNEL_MINOR_VERSION 1 17#define FUSE_KERNEL_MINOR_VERSION 1
@@ -52,12 +52,28 @@ struct fuse_kstatfs {
52 __u32 namelen; 52 __u32 namelen;
53}; 53};
54 54
55#define FATTR_MODE (1 << 0)
56#define FATTR_UID (1 << 1)
57#define FATTR_GID (1 << 2)
58#define FATTR_SIZE (1 << 3)
59#define FATTR_ATIME (1 << 4)
60#define FATTR_MTIME (1 << 5)
61#define FATTR_CTIME (1 << 6)
62
55enum fuse_opcode { 63enum fuse_opcode {
56 FUSE_LOOKUP = 1, 64 FUSE_LOOKUP = 1,
57 FUSE_FORGET = 2, /* no reply */ 65 FUSE_FORGET = 2, /* no reply */
58 FUSE_GETATTR = 3, 66 FUSE_GETATTR = 3,
67 FUSE_SETATTR = 4,
59 FUSE_READLINK = 5, 68 FUSE_READLINK = 5,
69 FUSE_SYMLINK = 6,
60 FUSE_GETDIR = 7, 70 FUSE_GETDIR = 7,
71 FUSE_MKNOD = 8,
72 FUSE_MKDIR = 9,
73 FUSE_UNLINK = 10,
74 FUSE_RMDIR = 11,
75 FUSE_RENAME = 12,
76 FUSE_LINK = 13,
61 FUSE_STATFS = 17, 77 FUSE_STATFS = 17,
62 FUSE_INIT = 26 78 FUSE_INIT = 26
63}; 79};
@@ -66,6 +82,7 @@ enum fuse_opcode {
66#define FUSE_MAX_IN 8192 82#define FUSE_MAX_IN 8192
67 83
68#define FUSE_NAME_MAX 1024 84#define FUSE_NAME_MAX 1024
85#define FUSE_SYMLINK_MAX 4096
69 86
70struct fuse_entry_out { 87struct fuse_entry_out {
71 __u64 nodeid; /* Inode ID */ 88 __u64 nodeid; /* Inode ID */
@@ -79,7 +96,7 @@ struct fuse_entry_out {
79}; 96};
80 97
81struct fuse_forget_in { 98struct fuse_forget_in {
82 __u64 version; 99 __u64 nlookup;
83}; 100};
84 101
85struct fuse_attr_out { 102struct fuse_attr_out {
@@ -93,6 +110,28 @@ struct fuse_getdir_out {
93 __u32 fd; 110 __u32 fd;
94}; 111};
95 112
113struct fuse_mknod_in {
114 __u32 mode;
115 __u32 rdev;
116};
117
118struct fuse_mkdir_in {
119 __u32 mode;
120};
121
122struct fuse_rename_in {
123 __u64 newdir;
124};
125
126struct fuse_link_in {
127 __u64 oldnodeid;
128};
129
130struct fuse_setattr_in {
131 __u32 valid;
132 struct fuse_attr attr;
133};
134
96struct fuse_statfs_out { 135struct fuse_statfs_out {
97 struct fuse_kstatfs st; 136 struct fuse_kstatfs st;
98}; 137};