diff options
author | Sage Weil <sage@newdream.net> | 2011-07-26 14:28:11 -0400 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2011-07-26 14:28:11 -0400 |
commit | 468640e32c7f6bfdaaa011095cc388786755d159 (patch) | |
tree | beb059d860c2ca39cda9ca3aa45603025655e1a6 /fs/ceph/file.c | |
parent | 9bae113a085b790de384bf86f09e15b42a65a985 (diff) |
ceph: fix ceph_lookup_open intent usage
We weren't properly calling lookup_instantiate_filp when setting up the
lookup intent, which could lead to file leakage on errors. So:
- use separate helper for the hidden snapdir translation, immediately
following the mds request
- use ceph_finish_lookup for the final dentry/return value dance in the
exit path
- lookup_instantiate_filp on success
Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Reviewed-by: Yehuda Sadeh <yehuda@hq.newdream.net>
Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph/file.c')
-rw-r--r-- | fs/ceph/file.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index e0115eb4e9ba..f34d47d66e7c 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -223,8 +223,9 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, | |||
223 | { | 223 | { |
224 | struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); | 224 | struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); |
225 | struct ceph_mds_client *mdsc = fsc->mdsc; | 225 | struct ceph_mds_client *mdsc = fsc->mdsc; |
226 | struct file *file = nd->intent.open.file; | 226 | struct file *file; |
227 | struct ceph_mds_request *req; | 227 | struct ceph_mds_request *req; |
228 | struct dentry *ret; | ||
228 | int err; | 229 | int err; |
229 | int flags = nd->intent.open.flags - 1; /* silly vfs! */ | 230 | int flags = nd->intent.open.flags - 1; /* silly vfs! */ |
230 | 231 | ||
@@ -245,15 +246,21 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, | |||
245 | err = ceph_mdsc_do_request(mdsc, | 246 | err = ceph_mdsc_do_request(mdsc, |
246 | (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, | 247 | (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, |
247 | req); | 248 | req); |
248 | dentry = ceph_finish_lookup(req, dentry, err); | 249 | err = ceph_handle_snapdir(req, dentry, err); |
249 | if (!err && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry) | 250 | if (err) |
251 | goto out; | ||
252 | if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry) | ||
250 | err = ceph_handle_notrace_create(dir, dentry); | 253 | err = ceph_handle_notrace_create(dir, dentry); |
251 | if (!err) | 254 | if (err) |
252 | err = ceph_init_file(req->r_dentry->d_inode, file, | 255 | goto out; |
253 | req->r_fmode); | 256 | file = lookup_instantiate_filp(nd, req->r_dentry, ceph_open); |
257 | if (IS_ERR(file)) | ||
258 | err = PTR_ERR(file); | ||
259 | out: | ||
260 | ret = ceph_finish_lookup(req, dentry, err); | ||
254 | ceph_mdsc_put_request(req); | 261 | ceph_mdsc_put_request(req); |
255 | dout("ceph_lookup_open result=%p\n", dentry); | 262 | dout("ceph_lookup_open result=%p\n", ret); |
256 | return dentry; | 263 | return ret; |
257 | } | 264 | } |
258 | 265 | ||
259 | int ceph_release(struct inode *inode, struct file *file) | 266 | int ceph_release(struct inode *inode, struct file *file) |