diff options
Diffstat (limited to 'fs/ceph/file.c')
-rw-r--r-- | fs/ceph/file.c | 62 |
1 files changed, 37 insertions, 25 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 1b81d6c3187..ecebbc09bfc 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/sched.h> | 4 | #include <linux/sched.h> |
5 | #include <linux/slab.h> | 5 | #include <linux/slab.h> |
6 | #include <linux/file.h> | 6 | #include <linux/file.h> |
7 | #include <linux/mount.h> | ||
7 | #include <linux/namei.h> | 8 | #include <linux/namei.h> |
8 | #include <linux/writeback.h> | 9 | #include <linux/writeback.h> |
9 | 10 | ||
@@ -106,9 +107,6 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode) | |||
106 | } | 107 | } |
107 | 108 | ||
108 | /* | 109 | /* |
109 | * If the filp already has private_data, that means the file was | ||
110 | * already opened by intent during lookup, and we do nothing. | ||
111 | * | ||
112 | * If we already have the requisite capabilities, we can satisfy | 110 | * If we already have the requisite capabilities, we can satisfy |
113 | * the open request locally (no need to request new caps from the | 111 | * the open request locally (no need to request new caps from the |
114 | * MDS). We do, however, need to inform the MDS (asynchronously) | 112 | * MDS). We do, however, need to inform the MDS (asynchronously) |
@@ -207,24 +205,29 @@ out: | |||
207 | 205 | ||
208 | 206 | ||
209 | /* | 207 | /* |
210 | * Do a lookup + open with a single request. | 208 | * Do a lookup + open with a single request. If we get a non-existent |
211 | * | 209 | * file or symlink, return 1 so the VFS can retry. |
212 | * If this succeeds, but some subsequent check in the vfs | ||
213 | * may_open() fails, the struct *file gets cleaned up (i.e. | ||
214 | * ceph_release gets called). So fear not! | ||
215 | */ | 210 | */ |
216 | int ceph_lookup_open(struct inode *dir, struct dentry *dentry, | 211 | int ceph_atomic_open(struct inode *dir, struct dentry *dentry, |
217 | struct file *file, unsigned flags, umode_t mode, | 212 | struct file *file, unsigned flags, umode_t mode, |
218 | int *opened) | 213 | int *opened) |
219 | { | 214 | { |
220 | struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); | 215 | struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); |
221 | struct ceph_mds_client *mdsc = fsc->mdsc; | 216 | struct ceph_mds_client *mdsc = fsc->mdsc; |
222 | struct ceph_mds_request *req; | 217 | struct ceph_mds_request *req; |
223 | struct dentry *ret; | 218 | struct dentry *dn; |
224 | int err; | 219 | int err; |
225 | 220 | ||
226 | dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n", | 221 | dout("atomic_open %p dentry %p '%.*s' %s flags %d mode 0%o\n", |
227 | dentry, dentry->d_name.len, dentry->d_name.name, flags, mode); | 222 | dir, dentry, dentry->d_name.len, dentry->d_name.name, |
223 | d_unhashed(dentry) ? "unhashed" : "hashed", flags, mode); | ||
224 | |||
225 | if (dentry->d_name.len > NAME_MAX) | ||
226 | return -ENAMETOOLONG; | ||
227 | |||
228 | err = ceph_init_dentry(dentry); | ||
229 | if (err < 0) | ||
230 | return err; | ||
228 | 231 | ||
229 | /* do the open */ | 232 | /* do the open */ |
230 | req = prepare_open_request(dir->i_sb, flags, mode); | 233 | req = prepare_open_request(dir->i_sb, flags, mode); |
@@ -241,22 +244,31 @@ int ceph_lookup_open(struct inode *dir, struct dentry *dentry, | |||
241 | (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, | 244 | (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, |
242 | req); | 245 | req); |
243 | err = ceph_handle_snapdir(req, dentry, err); | 246 | err = ceph_handle_snapdir(req, dentry, err); |
244 | if (err) | 247 | if (err == 0 && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry) |
245 | goto out; | ||
246 | if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry) | ||
247 | err = ceph_handle_notrace_create(dir, dentry); | 248 | err = ceph_handle_notrace_create(dir, dentry); |
248 | if (err) | ||
249 | goto out; | ||
250 | err = finish_open(file, req->r_dentry, ceph_open, opened); | ||
251 | out: | ||
252 | ret = ceph_finish_lookup(req, dentry, err); | ||
253 | ceph_mdsc_put_request(req); | ||
254 | dout("ceph_lookup_open result=%p\n", ret); | ||
255 | 249 | ||
256 | if (IS_ERR(ret)) | 250 | if (d_unhashed(dentry)) { |
257 | return PTR_ERR(ret); | 251 | dn = ceph_finish_lookup(req, dentry, err); |
252 | if (IS_ERR(dn)) | ||
253 | err = PTR_ERR(dn); | ||
254 | } else { | ||
255 | /* we were given a hashed negative dentry */ | ||
256 | dn = NULL; | ||
257 | } | ||
258 | if (err) | ||
259 | goto out_err; | ||
260 | if (dn || dentry->d_inode == NULL || S_ISLNK(dentry->d_inode->i_mode)) { | ||
261 | /* make vfs retry on splice, ENOENT, or symlink */ | ||
262 | dout("atomic_open finish_no_open on dn %p\n", dn); | ||
263 | err = finish_no_open(file, dn); | ||
264 | } else { | ||
265 | dout("atomic_open finish_open on dn %p\n", dn); | ||
266 | err = finish_open(file, dentry, ceph_open, opened); | ||
267 | } | ||
258 | 268 | ||
259 | dput(ret); | 269 | out_err: |
270 | ceph_mdsc_put_request(req); | ||
271 | dout("atomic_open result=%d\n", err); | ||
260 | return err; | 272 | return err; |
261 | } | 273 | } |
262 | 274 | ||