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 | ||
