diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index c4b7832c38b56f6d0a92e2f69e969492a7568831..75df600ec9b43b17d919f3a66cf3dcd36c735ff5 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -594,14 +594,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, if (err < 0) return ERR_PTR(err); - /* open (but not create!) intent? */ - if (nd && - (nd->flags & LOOKUP_OPEN) && - !(nd->intent.open.flags & O_CREAT)) { - int mode = nd->intent.open.create_mode & ~current->fs->umask; - return ceph_lookup_open(dir, dentry, nd, mode); - } - /* can we conclude ENOENT locally? */ if (dentry->d_inode == NULL) { struct ceph_inode_info *ci = ceph_inode(dir); @@ -642,6 +634,47 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, return dentry; } +struct file *ceph_atomic_open(struct inode *dir, struct dentry *dentry, + struct opendata *od, unsigned flags, umode_t mode, + bool *created) +{ + int err; + struct dentry *res = NULL; + struct file *filp; + + if (!(flags & O_CREAT)) { + if (dentry->d_name.len > NAME_MAX) + return ERR_PTR(-ENAMETOOLONG); + + err = ceph_init_dentry(dentry); + if (err < 0) + return ERR_PTR(err); + + return ceph_lookup_open(dir, dentry, od, flags, mode); + } + + if (d_unhashed(dentry)) { + res = ceph_lookup(dir, dentry, NULL); + if (IS_ERR(res)) + return ERR_CAST(res); + + if (res) + dentry = res; + } + + /* We don't deal with positive dentries here */ + if (dentry->d_inode) { + finish_no_open(od, res); + return NULL; + } + + *created = true; + filp = ceph_lookup_open(dir, dentry, od, flags, mode); + dput(res); + + return filp; +} + /* * If we do a create but get no trace back from the MDS, follow up with * a lookup (the VFS expects us to link up the provided dentry). @@ -702,23 +735,7 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd) { - dout("create in dir %p dentry %p name '%.*s'\n", - dir, dentry, dentry->d_name.len, dentry->d_name.name); - - if (ceph_snap(dir) != CEPH_NOSNAP) - return -EROFS; - - if (nd) { - BUG_ON((nd->flags & LOOKUP_OPEN) == 0); - dentry = ceph_lookup_open(dir, dentry, nd, mode); - /* hrm, what should i do here if we get aliased? */ - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - return 0; - } - - /* fall back to mknod */ - return ceph_mknod(dir, dentry, (mode & ~S_IFMT) | S_IFREG, 0); + return ceph_mknod(dir, dentry, mode, 0); } static int ceph_symlink(struct inode *dir, struct dentry *dentry, @@ -1357,6 +1374,7 @@ const struct inode_operations ceph_dir_iops = { .rmdir = ceph_unlink, .rename = ceph_rename, .create = ceph_create, + .atomic_open = ceph_atomic_open, }; const struct dentry_operations ceph_dentry_ops = { diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 4bf9773e6a36935aaf131a5211f8d6f0e3cf77d9..e34dc22e75a9b0a5e2ac56d2470cecb8b48e1087 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -213,21 +213,15 @@ int ceph_open(struct inode *inode, struct file *file) * may_open() fails, the struct *file gets cleaned up (i.e. * ceph_release gets called). So fear not! */ -/* - * flags - * path_lookup_open -> LOOKUP_OPEN - * path_lookup_create -> LOOKUP_OPEN|LOOKUP_CREATE - */ -struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, - struct nameidata *nd, int mode) +struct file *ceph_lookup_open(struct inode *dir, struct dentry *dentry, + struct opendata *od, unsigned flags, umode_t mode) { struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); struct ceph_mds_client *mdsc = fsc->mdsc; - struct file *file; + struct file *file = NULL; struct ceph_mds_request *req; struct dentry *ret; int err; - int flags = nd->intent.open.flags; dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n", dentry, dentry->d_name.len, dentry->d_name.name, flags, mode); @@ -253,14 +247,19 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, err = ceph_handle_notrace_create(dir, dentry); if (err) goto out; - file = lookup_instantiate_filp(nd, req->r_dentry, ceph_open); + file = finish_open(od, req->r_dentry, ceph_open); if (IS_ERR(file)) err = PTR_ERR(file); out: ret = ceph_finish_lookup(req, dentry, err); ceph_mdsc_put_request(req); dout("ceph_lookup_open result=%p\n", ret); - return ret; + + if (IS_ERR(ret)) + return ERR_CAST(ret); + + dput(ret); + return err ? ERR_PTR(err) : file; } int ceph_release(struct inode *inode, struct file *file) diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 8471db98b62c8b28578a596e822ddd357aac7168..e61e54673e561b4c52b02f9e035cf80af7024a68 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -806,8 +806,9 @@ extern int ceph_copy_from_page_vector(struct page **pages, loff_t off, size_t len); extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); extern int ceph_open(struct inode *inode, struct file *file); -extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry, - struct nameidata *nd, int mode); +extern struct file *ceph_lookup_open(struct inode *dir, struct dentry *dentry, + struct opendata *od, unsigned flags, + umode_t mode); extern int ceph_release(struct inode *inode, struct file *filp); /* dir.c */