diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fuse/dir.c | 52 |
1 files changed, 38 insertions, 14 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index cfc8f81e60d0..c71a6c092ad9 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -138,6 +138,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
138 | struct fuse_entry_out outarg; | 138 | struct fuse_entry_out outarg; |
139 | struct fuse_conn *fc; | 139 | struct fuse_conn *fc; |
140 | struct fuse_req *req; | 140 | struct fuse_req *req; |
141 | struct fuse_req *forget_req; | ||
141 | struct dentry *parent; | 142 | struct dentry *parent; |
142 | 143 | ||
143 | /* Doesn't hurt to "reset" the validity timeout */ | 144 | /* Doesn't hurt to "reset" the validity timeout */ |
@@ -152,25 +153,33 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
152 | if (IS_ERR(req)) | 153 | if (IS_ERR(req)) |
153 | return 0; | 154 | return 0; |
154 | 155 | ||
156 | forget_req = fuse_get_req(fc); | ||
157 | if (IS_ERR(forget_req)) { | ||
158 | fuse_put_request(fc, req); | ||
159 | return 0; | ||
160 | } | ||
161 | |||
155 | parent = dget_parent(entry); | 162 | parent = dget_parent(entry); |
156 | fuse_lookup_init(req, parent->d_inode, entry, &outarg); | 163 | fuse_lookup_init(req, parent->d_inode, entry, &outarg); |
157 | request_send(fc, req); | 164 | request_send(fc, req); |
158 | dput(parent); | 165 | dput(parent); |
159 | err = req->out.h.error; | 166 | err = req->out.h.error; |
167 | fuse_put_request(fc, req); | ||
160 | /* Zero nodeid is same as -ENOENT */ | 168 | /* Zero nodeid is same as -ENOENT */ |
161 | if (!err && !outarg.nodeid) | 169 | if (!err && !outarg.nodeid) |
162 | err = -ENOENT; | 170 | err = -ENOENT; |
163 | if (!err) { | 171 | if (!err) { |
164 | struct fuse_inode *fi = get_fuse_inode(inode); | 172 | struct fuse_inode *fi = get_fuse_inode(inode); |
165 | if (outarg.nodeid != get_node_id(inode)) { | 173 | if (outarg.nodeid != get_node_id(inode)) { |
166 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 174 | fuse_send_forget(fc, forget_req, |
175 | outarg.nodeid, 1); | ||
167 | return 0; | 176 | return 0; |
168 | } | 177 | } |
169 | spin_lock(&fc->lock); | 178 | spin_lock(&fc->lock); |
170 | fi->nlookup ++; | 179 | fi->nlookup ++; |
171 | spin_unlock(&fc->lock); | 180 | spin_unlock(&fc->lock); |
172 | } | 181 | } |
173 | fuse_put_request(fc, req); | 182 | fuse_put_request(fc, forget_req); |
174 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) | 183 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) |
175 | return 0; | 184 | return 0; |
176 | 185 | ||
@@ -221,6 +230,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
221 | struct inode *inode = NULL; | 230 | struct inode *inode = NULL; |
222 | struct fuse_conn *fc = get_fuse_conn(dir); | 231 | struct fuse_conn *fc = get_fuse_conn(dir); |
223 | struct fuse_req *req; | 232 | struct fuse_req *req; |
233 | struct fuse_req *forget_req; | ||
224 | 234 | ||
225 | if (entry->d_name.len > FUSE_NAME_MAX) | 235 | if (entry->d_name.len > FUSE_NAME_MAX) |
226 | return ERR_PTR(-ENAMETOOLONG); | 236 | return ERR_PTR(-ENAMETOOLONG); |
@@ -229,9 +239,16 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
229 | if (IS_ERR(req)) | 239 | if (IS_ERR(req)) |
230 | return ERR_PTR(PTR_ERR(req)); | 240 | return ERR_PTR(PTR_ERR(req)); |
231 | 241 | ||
242 | forget_req = fuse_get_req(fc); | ||
243 | if (IS_ERR(forget_req)) { | ||
244 | fuse_put_request(fc, req); | ||
245 | return ERR_PTR(PTR_ERR(forget_req)); | ||
246 | } | ||
247 | |||
232 | fuse_lookup_init(req, dir, entry, &outarg); | 248 | fuse_lookup_init(req, dir, entry, &outarg); |
233 | request_send(fc, req); | 249 | request_send(fc, req); |
234 | err = req->out.h.error; | 250 | err = req->out.h.error; |
251 | fuse_put_request(fc, req); | ||
235 | /* Zero nodeid is same as -ENOENT, but with valid timeout */ | 252 | /* Zero nodeid is same as -ENOENT, but with valid timeout */ |
236 | if (!err && outarg.nodeid && | 253 | if (!err && outarg.nodeid && |
237 | (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) | 254 | (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) |
@@ -240,11 +257,11 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
240 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 257 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
241 | &outarg.attr); | 258 | &outarg.attr); |
242 | if (!inode) { | 259 | if (!inode) { |
243 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 260 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); |
244 | return ERR_PTR(-ENOMEM); | 261 | return ERR_PTR(-ENOMEM); |
245 | } | 262 | } |
246 | } | 263 | } |
247 | fuse_put_request(fc, req); | 264 | fuse_put_request(fc, forget_req); |
248 | if (err && err != -ENOENT) | 265 | if (err && err != -ENOENT) |
249 | return ERR_PTR(err); | 266 | return ERR_PTR(err); |
250 | 267 | ||
@@ -388,6 +405,13 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
388 | struct fuse_entry_out outarg; | 405 | struct fuse_entry_out outarg; |
389 | struct inode *inode; | 406 | struct inode *inode; |
390 | int err; | 407 | int err; |
408 | struct fuse_req *forget_req; | ||
409 | |||
410 | forget_req = fuse_get_req(fc); | ||
411 | if (IS_ERR(forget_req)) { | ||
412 | fuse_put_request(fc, req); | ||
413 | return PTR_ERR(forget_req); | ||
414 | } | ||
391 | 415 | ||
392 | req->in.h.nodeid = get_node_id(dir); | 416 | req->in.h.nodeid = get_node_id(dir); |
393 | req->out.numargs = 1; | 417 | req->out.numargs = 1; |
@@ -395,24 +419,24 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
395 | req->out.args[0].value = &outarg; | 419 | req->out.args[0].value = &outarg; |
396 | request_send(fc, req); | 420 | request_send(fc, req); |
397 | err = req->out.h.error; | 421 | err = req->out.h.error; |
398 | if (err) { | 422 | fuse_put_request(fc, req); |
399 | fuse_put_request(fc, req); | 423 | if (err) |
400 | return err; | 424 | goto out_put_forget_req; |
401 | } | 425 | |
402 | err = -EIO; | 426 | err = -EIO; |
403 | if (invalid_nodeid(outarg.nodeid)) | 427 | if (invalid_nodeid(outarg.nodeid)) |
404 | goto out_put_request; | 428 | goto out_put_forget_req; |
405 | 429 | ||
406 | if ((outarg.attr.mode ^ mode) & S_IFMT) | 430 | if ((outarg.attr.mode ^ mode) & S_IFMT) |
407 | goto out_put_request; | 431 | goto out_put_forget_req; |
408 | 432 | ||
409 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 433 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
410 | &outarg.attr); | 434 | &outarg.attr); |
411 | if (!inode) { | 435 | if (!inode) { |
412 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 436 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); |
413 | return -ENOMEM; | 437 | return -ENOMEM; |
414 | } | 438 | } |
415 | fuse_put_request(fc, req); | 439 | fuse_put_request(fc, forget_req); |
416 | 440 | ||
417 | if (S_ISDIR(inode->i_mode)) { | 441 | if (S_ISDIR(inode->i_mode)) { |
418 | struct dentry *alias; | 442 | struct dentry *alias; |
@@ -434,8 +458,8 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
434 | fuse_invalidate_attr(dir); | 458 | fuse_invalidate_attr(dir); |
435 | return 0; | 459 | return 0; |
436 | 460 | ||
437 | out_put_request: | 461 | out_put_forget_req: |
438 | fuse_put_request(fc, req); | 462 | fuse_put_request(fc, forget_req); |
439 | return err; | 463 | return err; |
440 | } | 464 | } |
441 | 465 | ||