diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 294 |
1 files changed, 184 insertions, 110 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 51f5da652771..21fd59c7bc24 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -13,15 +13,66 @@ | |||
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> | ||
17 | 16 | ||
18 | static inline unsigned long time_to_jiffies(unsigned long sec, | 17 | /* |
19 | unsigned long nsec) | 18 | * FUSE caches dentries and attributes with separate timeout. The |
19 | * time in jiffies until the dentry/attributes are valid is stored in | ||
20 | * dentry->d_time and fuse_inode->i_time respectively. | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * Calculate the time in jiffies until a dentry/attributes are valid | ||
25 | */ | ||
26 | static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec) | ||
20 | { | 27 | { |
21 | struct timespec ts = {sec, nsec}; | 28 | struct timespec ts = {sec, nsec}; |
22 | return jiffies + timespec_to_jiffies(&ts); | 29 | return jiffies + timespec_to_jiffies(&ts); |
23 | } | 30 | } |
24 | 31 | ||
32 | /* | ||
33 | * Set dentry and possibly attribute timeouts from the lookup/mk* | ||
34 | * replies | ||
35 | */ | ||
36 | static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) | ||
37 | { | ||
38 | entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); | ||
39 | if (entry->d_inode) | ||
40 | get_fuse_inode(entry->d_inode)->i_time = | ||
41 | time_to_jiffies(o->attr_valid, o->attr_valid_nsec); | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * Mark the attributes as stale, so that at the next call to | ||
46 | * ->getattr() they will be fetched from userspace | ||
47 | */ | ||
48 | void fuse_invalidate_attr(struct inode *inode) | ||
49 | { | ||
50 | get_fuse_inode(inode)->i_time = jiffies - 1; | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * Just mark the entry as stale, so that a next attempt to look it up | ||
55 | * will result in a new lookup call to userspace | ||
56 | * | ||
57 | * This is called when a dentry is about to become negative and the | ||
58 | * timeout is unknown (unlink, rmdir, rename and in some cases | ||
59 | * lookup) | ||
60 | */ | ||
61 | static void fuse_invalidate_entry_cache(struct dentry *entry) | ||
62 | { | ||
63 | entry->d_time = jiffies - 1; | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * Same as fuse_invalidate_entry_cache(), but also try to remove the | ||
68 | * dentry from the hash | ||
69 | */ | ||
70 | static void fuse_invalidate_entry(struct dentry *entry) | ||
71 | { | ||
72 | d_invalidate(entry); | ||
73 | fuse_invalidate_entry_cache(entry); | ||
74 | } | ||
75 | |||
25 | static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, | 76 | static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, |
26 | struct dentry *entry, | 77 | struct dentry *entry, |
27 | struct fuse_entry_out *outarg) | 78 | struct fuse_entry_out *outarg) |
@@ -37,17 +88,34 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, | |||
37 | req->out.args[0].value = outarg; | 88 | req->out.args[0].value = outarg; |
38 | } | 89 | } |
39 | 90 | ||
91 | /* | ||
92 | * Check whether the dentry is still valid | ||
93 | * | ||
94 | * If the entry validity timeout has expired and the dentry is | ||
95 | * positive, try to redo the lookup. If the lookup results in a | ||
96 | * different inode, then let the VFS invalidate the dentry and redo | ||
97 | * the lookup once more. If the lookup results in the same inode, | ||
98 | * then refresh the attributes, timeouts and mark the dentry valid. | ||
99 | */ | ||
40 | static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | 100 | static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) |
41 | { | 101 | { |
42 | if (!entry->d_inode || is_bad_inode(entry->d_inode)) | 102 | struct inode *inode = entry->d_inode; |
103 | |||
104 | if (inode && is_bad_inode(inode)) | ||
43 | return 0; | 105 | return 0; |
44 | else if (time_after(jiffies, entry->d_time)) { | 106 | else if (time_after(jiffies, entry->d_time)) { |
45 | int err; | 107 | int err; |
46 | struct fuse_entry_out outarg; | 108 | struct fuse_entry_out outarg; |
47 | struct inode *inode = entry->d_inode; | 109 | struct fuse_conn *fc; |
48 | struct fuse_inode *fi = get_fuse_inode(inode); | 110 | struct fuse_req *req; |
49 | struct fuse_conn *fc = get_fuse_conn(inode); | 111 | |
50 | struct fuse_req *req = fuse_get_request(fc); | 112 | /* Doesn't hurt to "reset" the validity timeout */ |
113 | fuse_invalidate_entry_cache(entry); | ||
114 | if (!inode) | ||
115 | return 0; | ||
116 | |||
117 | fc = get_fuse_conn(inode); | ||
118 | req = fuse_get_request(fc); | ||
51 | if (!req) | 119 | if (!req) |
52 | return 0; | 120 | return 0; |
53 | 121 | ||
@@ -55,6 +123,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
55 | request_send(fc, req); | 123 | request_send(fc, req); |
56 | err = req->out.h.error; | 124 | err = req->out.h.error; |
57 | if (!err) { | 125 | if (!err) { |
126 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
58 | if (outarg.nodeid != get_node_id(inode)) { | 127 | if (outarg.nodeid != get_node_id(inode)) { |
59 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 128 | fuse_send_forget(fc, req, outarg.nodeid, 1); |
60 | return 0; | 129 | return 0; |
@@ -66,18 +135,18 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
66 | return 0; | 135 | return 0; |
67 | 136 | ||
68 | fuse_change_attributes(inode, &outarg.attr); | 137 | fuse_change_attributes(inode, &outarg.attr); |
69 | entry->d_time = time_to_jiffies(outarg.entry_valid, | 138 | fuse_change_timeout(entry, &outarg); |
70 | outarg.entry_valid_nsec); | ||
71 | fi->i_time = time_to_jiffies(outarg.attr_valid, | ||
72 | outarg.attr_valid_nsec); | ||
73 | } | 139 | } |
74 | return 1; | 140 | return 1; |
75 | } | 141 | } |
76 | 142 | ||
143 | /* | ||
144 | * Check if there's already a hashed alias of this directory inode. | ||
145 | * If yes, then lookup and mkdir must not create a new alias. | ||
146 | */ | ||
77 | static int dir_alias(struct inode *inode) | 147 | static int dir_alias(struct inode *inode) |
78 | { | 148 | { |
79 | if (S_ISDIR(inode->i_mode)) { | 149 | if (S_ISDIR(inode->i_mode)) { |
80 | /* Don't allow creating an alias to a directory */ | ||
81 | struct dentry *alias = d_find_alias(inode); | 150 | struct dentry *alias = d_find_alias(inode); |
82 | if (alias) { | 151 | if (alias) { |
83 | dput(alias); | 152 | dput(alias); |
@@ -87,7 +156,7 @@ static int dir_alias(struct inode *inode) | |||
87 | return 0; | 156 | return 0; |
88 | } | 157 | } |
89 | 158 | ||
90 | static inline int invalid_nodeid(u64 nodeid) | 159 | static int invalid_nodeid(u64 nodeid) |
91 | { | 160 | { |
92 | return !nodeid || nodeid == FUSE_ROOT_ID; | 161 | return !nodeid || nodeid == FUSE_ROOT_ID; |
93 | } | 162 | } |
@@ -96,8 +165,14 @@ static struct dentry_operations fuse_dentry_operations = { | |||
96 | .d_revalidate = fuse_dentry_revalidate, | 165 | .d_revalidate = fuse_dentry_revalidate, |
97 | }; | 166 | }; |
98 | 167 | ||
99 | static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, | 168 | static int valid_mode(int m) |
100 | struct inode **inodep) | 169 | { |
170 | return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) || | ||
171 | S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); | ||
172 | } | ||
173 | |||
174 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | ||
175 | struct nameidata *nd) | ||
101 | { | 176 | { |
102 | int err; | 177 | int err; |
103 | struct fuse_entry_out outarg; | 178 | struct fuse_entry_out outarg; |
@@ -106,53 +181,49 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, | |||
106 | struct fuse_req *req; | 181 | struct fuse_req *req; |
107 | 182 | ||
108 | if (entry->d_name.len > FUSE_NAME_MAX) | 183 | if (entry->d_name.len > FUSE_NAME_MAX) |
109 | return -ENAMETOOLONG; | 184 | return ERR_PTR(-ENAMETOOLONG); |
110 | 185 | ||
111 | req = fuse_get_request(fc); | 186 | req = fuse_get_request(fc); |
112 | if (!req) | 187 | if (!req) |
113 | return -EINTR; | 188 | return ERR_PTR(-EINTR); |
114 | 189 | ||
115 | fuse_lookup_init(req, dir, entry, &outarg); | 190 | fuse_lookup_init(req, dir, entry, &outarg); |
116 | request_send(fc, req); | 191 | request_send(fc, req); |
117 | err = req->out.h.error; | 192 | err = req->out.h.error; |
118 | if (!err && invalid_nodeid(outarg.nodeid)) | 193 | if (!err && ((outarg.nodeid && invalid_nodeid(outarg.nodeid)) || |
194 | !valid_mode(outarg.attr.mode))) | ||
119 | err = -EIO; | 195 | err = -EIO; |
120 | if (!err) { | 196 | if (!err && outarg.nodeid) { |
121 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 197 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
122 | &outarg.attr); | 198 | &outarg.attr); |
123 | if (!inode) { | 199 | if (!inode) { |
124 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 200 | fuse_send_forget(fc, req, outarg.nodeid, 1); |
125 | return -ENOMEM; | 201 | return ERR_PTR(-ENOMEM); |
126 | } | 202 | } |
127 | } | 203 | } |
128 | fuse_put_request(fc, req); | 204 | fuse_put_request(fc, req); |
129 | if (err && err != -ENOENT) | 205 | if (err && err != -ENOENT) |
130 | return err; | 206 | return ERR_PTR(err); |
131 | 207 | ||
132 | if (inode) { | 208 | if (inode && dir_alias(inode)) { |
133 | struct fuse_inode *fi = get_fuse_inode(inode); | 209 | iput(inode); |
134 | entry->d_time = time_to_jiffies(outarg.entry_valid, | 210 | return ERR_PTR(-EIO); |
135 | outarg.entry_valid_nsec); | ||
136 | fi->i_time = time_to_jiffies(outarg.attr_valid, | ||
137 | outarg.attr_valid_nsec); | ||
138 | } | 211 | } |
139 | 212 | d_add(entry, inode); | |
140 | entry->d_op = &fuse_dentry_operations; | 213 | entry->d_op = &fuse_dentry_operations; |
141 | *inodep = inode; | 214 | if (!err) |
142 | return 0; | 215 | fuse_change_timeout(entry, &outarg); |
143 | } | 216 | else |
144 | 217 | fuse_invalidate_entry_cache(entry); | |
145 | void fuse_invalidate_attr(struct inode *inode) | 218 | return NULL; |
146 | { | ||
147 | get_fuse_inode(inode)->i_time = jiffies - 1; | ||
148 | } | ||
149 | |||
150 | static void fuse_invalidate_entry(struct dentry *entry) | ||
151 | { | ||
152 | d_invalidate(entry); | ||
153 | entry->d_time = jiffies - 1; | ||
154 | } | 219 | } |
155 | 220 | ||
221 | /* | ||
222 | * Atomic create+open operation | ||
223 | * | ||
224 | * If the filesystem doesn't support this, then fall back to separate | ||
225 | * 'mknod' + 'open' requests. | ||
226 | */ | ||
156 | static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | 227 | static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, |
157 | struct nameidata *nd) | 228 | struct nameidata *nd) |
158 | { | 229 | { |
@@ -163,7 +234,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
163 | struct fuse_open_in inarg; | 234 | struct fuse_open_in inarg; |
164 | struct fuse_open_out outopen; | 235 | struct fuse_open_out outopen; |
165 | struct fuse_entry_out outentry; | 236 | struct fuse_entry_out outentry; |
166 | struct fuse_inode *fi; | ||
167 | struct fuse_file *ff; | 237 | struct fuse_file *ff; |
168 | struct file *file; | 238 | struct file *file; |
169 | int flags = nd->intent.open.flags - 1; | 239 | int flags = nd->intent.open.flags - 1; |
@@ -172,10 +242,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
172 | if (fc->no_create) | 242 | if (fc->no_create) |
173 | goto out; | 243 | goto out; |
174 | 244 | ||
175 | err = -ENAMETOOLONG; | ||
176 | if (entry->d_name.len > FUSE_NAME_MAX) | ||
177 | goto out; | ||
178 | |||
179 | err = -EINTR; | 245 | err = -EINTR; |
180 | req = fuse_get_request(fc); | 246 | req = fuse_get_request(fc); |
181 | if (!req) | 247 | if (!req) |
@@ -220,17 +286,15 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
220 | if (!inode) { | 286 | if (!inode) { |
221 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 287 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
222 | ff->fh = outopen.fh; | 288 | ff->fh = outopen.fh; |
289 | /* Special release, with inode = NULL, this will | ||
290 | trigger a 'forget' request when the release is | ||
291 | complete */ | ||
223 | fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); | 292 | fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); |
224 | goto out_put_request; | 293 | goto out_put_request; |
225 | } | 294 | } |
226 | fuse_put_request(fc, req); | 295 | fuse_put_request(fc, req); |
227 | entry->d_time = time_to_jiffies(outentry.entry_valid, | ||
228 | outentry.entry_valid_nsec); | ||
229 | fi = get_fuse_inode(inode); | ||
230 | fi->i_time = time_to_jiffies(outentry.attr_valid, | ||
231 | outentry.attr_valid_nsec); | ||
232 | |||
233 | d_instantiate(entry, inode); | 296 | d_instantiate(entry, inode); |
297 | fuse_change_timeout(entry, &outentry); | ||
234 | file = lookup_instantiate_filp(nd, entry, generic_file_open); | 298 | file = lookup_instantiate_filp(nd, entry, generic_file_open); |
235 | if (IS_ERR(file)) { | 299 | if (IS_ERR(file)) { |
236 | ff->fh = outopen.fh; | 300 | ff->fh = outopen.fh; |
@@ -248,13 +312,15 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
248 | return err; | 312 | return err; |
249 | } | 313 | } |
250 | 314 | ||
315 | /* | ||
316 | * Code shared between mknod, mkdir, symlink and link | ||
317 | */ | ||
251 | static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | 318 | static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, |
252 | struct inode *dir, struct dentry *entry, | 319 | struct inode *dir, struct dentry *entry, |
253 | int mode) | 320 | int mode) |
254 | { | 321 | { |
255 | struct fuse_entry_out outarg; | 322 | struct fuse_entry_out outarg; |
256 | struct inode *inode; | 323 | struct inode *inode; |
257 | struct fuse_inode *fi; | ||
258 | int err; | 324 | int err; |
259 | 325 | ||
260 | req->in.h.nodeid = get_node_id(dir); | 326 | req->in.h.nodeid = get_node_id(dir); |
@@ -268,10 +334,13 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
268 | fuse_put_request(fc, req); | 334 | fuse_put_request(fc, req); |
269 | return err; | 335 | return err; |
270 | } | 336 | } |
271 | if (invalid_nodeid(outarg.nodeid)) { | 337 | err = -EIO; |
272 | fuse_put_request(fc, req); | 338 | if (invalid_nodeid(outarg.nodeid)) |
273 | return -EIO; | 339 | goto out_put_request; |
274 | } | 340 | |
341 | if ((outarg.attr.mode ^ mode) & S_IFMT) | ||
342 | goto out_put_request; | ||
343 | |||
275 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 344 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
276 | &outarg.attr); | 345 | &outarg.attr); |
277 | if (!inode) { | 346 | if (!inode) { |
@@ -280,22 +349,19 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
280 | } | 349 | } |
281 | fuse_put_request(fc, req); | 350 | fuse_put_request(fc, req); |
282 | 351 | ||
283 | /* Don't allow userspace to do really stupid things... */ | 352 | if (dir_alias(inode)) { |
284 | if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) { | ||
285 | iput(inode); | 353 | iput(inode); |
286 | return -EIO; | 354 | return -EIO; |
287 | } | 355 | } |
288 | 356 | ||
289 | entry->d_time = time_to_jiffies(outarg.entry_valid, | ||
290 | outarg.entry_valid_nsec); | ||
291 | |||
292 | fi = get_fuse_inode(inode); | ||
293 | fi->i_time = time_to_jiffies(outarg.attr_valid, | ||
294 | outarg.attr_valid_nsec); | ||
295 | |||
296 | d_instantiate(entry, inode); | 357 | d_instantiate(entry, inode); |
358 | fuse_change_timeout(entry, &outarg); | ||
297 | fuse_invalidate_attr(dir); | 359 | fuse_invalidate_attr(dir); |
298 | return 0; | 360 | return 0; |
361 | |||
362 | out_put_request: | ||
363 | fuse_put_request(fc, req); | ||
364 | return err; | ||
299 | } | 365 | } |
300 | 366 | ||
301 | static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, | 367 | static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, |
@@ -355,12 +421,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry, | |||
355 | { | 421 | { |
356 | struct fuse_conn *fc = get_fuse_conn(dir); | 422 | struct fuse_conn *fc = get_fuse_conn(dir); |
357 | unsigned len = strlen(link) + 1; | 423 | unsigned len = strlen(link) + 1; |
358 | struct fuse_req *req; | 424 | struct fuse_req *req = fuse_get_request(fc); |
359 | |||
360 | if (len > FUSE_SYMLINK_MAX) | ||
361 | return -ENAMETOOLONG; | ||
362 | |||
363 | req = fuse_get_request(fc); | ||
364 | if (!req) | 425 | if (!req) |
365 | return -EINTR; | 426 | return -EINTR; |
366 | 427 | ||
@@ -399,6 +460,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) | |||
399 | inode->i_nlink = 0; | 460 | inode->i_nlink = 0; |
400 | fuse_invalidate_attr(inode); | 461 | fuse_invalidate_attr(inode); |
401 | fuse_invalidate_attr(dir); | 462 | fuse_invalidate_attr(dir); |
463 | fuse_invalidate_entry_cache(entry); | ||
402 | } else if (err == -EINTR) | 464 | } else if (err == -EINTR) |
403 | fuse_invalidate_entry(entry); | 465 | fuse_invalidate_entry(entry); |
404 | return err; | 466 | return err; |
@@ -424,6 +486,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) | |||
424 | if (!err) { | 486 | if (!err) { |
425 | entry->d_inode->i_nlink = 0; | 487 | entry->d_inode->i_nlink = 0; |
426 | fuse_invalidate_attr(dir); | 488 | fuse_invalidate_attr(dir); |
489 | fuse_invalidate_entry_cache(entry); | ||
427 | } else if (err == -EINTR) | 490 | } else if (err == -EINTR) |
428 | fuse_invalidate_entry(entry); | 491 | fuse_invalidate_entry(entry); |
429 | return err; | 492 | return err; |
@@ -459,6 +522,10 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, | |||
459 | fuse_invalidate_attr(olddir); | 522 | fuse_invalidate_attr(olddir); |
460 | if (olddir != newdir) | 523 | if (olddir != newdir) |
461 | fuse_invalidate_attr(newdir); | 524 | fuse_invalidate_attr(newdir); |
525 | |||
526 | /* newent will end up negative */ | ||
527 | if (newent->d_inode) | ||
528 | fuse_invalidate_entry_cache(newent); | ||
462 | } else if (err == -EINTR) { | 529 | } else if (err == -EINTR) { |
463 | /* If request was interrupted, DEITY only knows if the | 530 | /* If request was interrupted, DEITY only knows if the |
464 | rename actually took place. If the invalidation | 531 | rename actually took place. If the invalidation |
@@ -566,6 +633,15 @@ static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) | |||
566 | return 0; | 633 | return 0; |
567 | } | 634 | } |
568 | 635 | ||
636 | /* | ||
637 | * Check whether the inode attributes are still valid | ||
638 | * | ||
639 | * If the attribute validity timeout has expired, then fetch the fresh | ||
640 | * attributes with a 'getattr' request | ||
641 | * | ||
642 | * I'm not sure why cached attributes are never returned for the root | ||
643 | * inode, this is probably being too cautious. | ||
644 | */ | ||
569 | static int fuse_revalidate(struct dentry *entry) | 645 | static int fuse_revalidate(struct dentry *entry) |
570 | { | 646 | { |
571 | struct inode *inode = entry->d_inode; | 647 | struct inode *inode = entry->d_inode; |
@@ -613,6 +689,19 @@ static int fuse_access(struct inode *inode, int mask) | |||
613 | return err; | 689 | return err; |
614 | } | 690 | } |
615 | 691 | ||
692 | /* | ||
693 | * Check permission. The two basic access models of FUSE are: | ||
694 | * | ||
695 | * 1) Local access checking ('default_permissions' mount option) based | ||
696 | * on file mode. This is the plain old disk filesystem permission | ||
697 | * modell. | ||
698 | * | ||
699 | * 2) "Remote" access checking, where server is responsible for | ||
700 | * checking permission in each inode operation. An exception to this | ||
701 | * is if ->permission() was invoked from sys_access() in which case an | ||
702 | * access request is sent. Execute permission is still checked | ||
703 | * locally based on file mode. | ||
704 | */ | ||
616 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | 705 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) |
617 | { | 706 | { |
618 | struct fuse_conn *fc = get_fuse_conn(inode); | 707 | struct fuse_conn *fc = get_fuse_conn(inode); |
@@ -631,14 +720,10 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
631 | err = generic_permission(inode, mask, NULL); | 720 | err = generic_permission(inode, mask, NULL); |
632 | } | 721 | } |
633 | 722 | ||
634 | /* FIXME: Need some mechanism to revoke permissions: | 723 | /* Note: the opposite of the above test does not |
635 | currently if the filesystem suddenly changes the | 724 | exist. So if permissions are revoked this won't be |
636 | file mode, we will not be informed about it, and | 725 | noticed immediately, only after the attribute |
637 | continue to allow access to the file/directory. | 726 | timeout has expired */ |
638 | |||
639 | This is actually not so grave, since the user can | ||
640 | simply keep access to the file/directory anyway by | ||
641 | keeping it open... */ | ||
642 | 727 | ||
643 | return err; | 728 | return err; |
644 | } else { | 729 | } else { |
@@ -677,13 +762,6 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file, | |||
677 | return 0; | 762 | return 0; |
678 | } | 763 | } |
679 | 764 | ||
680 | static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file, | ||
681 | struct inode *inode, loff_t pos, | ||
682 | size_t count) | ||
683 | { | ||
684 | return fuse_send_read_common(req, file, inode, pos, count, 1); | ||
685 | } | ||
686 | |||
687 | static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | 765 | static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) |
688 | { | 766 | { |
689 | int err; | 767 | int err; |
@@ -691,7 +769,12 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
691 | struct page *page; | 769 | struct page *page; |
692 | struct inode *inode = file->f_dentry->d_inode; | 770 | struct inode *inode = file->f_dentry->d_inode; |
693 | struct fuse_conn *fc = get_fuse_conn(inode); | 771 | struct fuse_conn *fc = get_fuse_conn(inode); |
694 | struct fuse_req *req = fuse_get_request(fc); | 772 | struct fuse_req *req; |
773 | |||
774 | if (is_bad_inode(inode)) | ||
775 | return -EIO; | ||
776 | |||
777 | req = fuse_get_request(fc); | ||
695 | if (!req) | 778 | if (!req) |
696 | return -EINTR; | 779 | return -EINTR; |
697 | 780 | ||
@@ -702,7 +785,9 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
702 | } | 785 | } |
703 | req->num_pages = 1; | 786 | req->num_pages = 1; |
704 | req->pages[0] = page; | 787 | req->pages[0] = page; |
705 | nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE); | 788 | fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); |
789 | request_send(fc, req); | ||
790 | nbytes = req->out.args[0].size; | ||
706 | err = req->out.h.error; | 791 | err = req->out.h.error; |
707 | fuse_put_request(fc, req); | 792 | fuse_put_request(fc, req); |
708 | if (!err) | 793 | if (!err) |
@@ -806,6 +891,15 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) | |||
806 | } | 891 | } |
807 | } | 892 | } |
808 | 893 | ||
894 | /* | ||
895 | * Set attributes, and at the same time refresh them. | ||
896 | * | ||
897 | * Truncation is slightly complicated, because the 'truncate' request | ||
898 | * may fail, in which case we don't want to touch the mapping. | ||
899 | * vmtruncate() doesn't allow for this case. So do the rlimit | ||
900 | * checking by hand and call vmtruncate() only after the file has | ||
901 | * actually been truncated. | ||
902 | */ | ||
809 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) | 903 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) |
810 | { | 904 | { |
811 | struct inode *inode = entry->d_inode; | 905 | struct inode *inode = entry->d_inode; |
@@ -883,23 +977,6 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, | |||
883 | return err; | 977 | return err; |
884 | } | 978 | } |
885 | 979 | ||
886 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | ||
887 | struct nameidata *nd) | ||
888 | { | ||
889 | struct inode *inode; | ||
890 | int err; | ||
891 | |||
892 | err = fuse_lookup_iget(dir, entry, &inode); | ||
893 | if (err) | ||
894 | return ERR_PTR(err); | ||
895 | if (inode && dir_alias(inode)) { | ||
896 | iput(inode); | ||
897 | return ERR_PTR(-EIO); | ||
898 | } | ||
899 | d_add(entry, inode); | ||
900 | return NULL; | ||
901 | } | ||
902 | |||
903 | static int fuse_setxattr(struct dentry *entry, const char *name, | 980 | static int fuse_setxattr(struct dentry *entry, const char *name, |
904 | const void *value, size_t size, int flags) | 981 | const void *value, size_t size, int flags) |
905 | { | 982 | { |
@@ -909,9 +986,6 @@ static int fuse_setxattr(struct dentry *entry, const char *name, | |||
909 | struct fuse_setxattr_in inarg; | 986 | struct fuse_setxattr_in inarg; |
910 | int err; | 987 | int err; |
911 | 988 | ||
912 | if (size > FUSE_XATTR_SIZE_MAX) | ||
913 | return -E2BIG; | ||
914 | |||
915 | if (fc->no_setxattr) | 989 | if (fc->no_setxattr) |
916 | return -EOPNOTSUPP; | 990 | return -EOPNOTSUPP; |
917 | 991 | ||