Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d83bde9 authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Al Viro
Browse files

ceph: implement i_op->atomic_open()



Add an ->atomic_open implementation which replaces the atomic lookup+open+create
operation implemented via ->lookup and ->create operations.

Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
CC: Sage Weil <sage@newdream.net>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 3819219b
Loading
Loading
Loading
Loading
+43 −25
Original line number Original line Diff line number Diff line
@@ -594,14 +594,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
	if (err < 0)
	if (err < 0)
		return ERR_PTR(err);
		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? */
	/* can we conclude ENOENT locally? */
	if (dentry->d_inode == NULL) {
	if (dentry->d_inode == NULL) {
		struct ceph_inode_info *ci = ceph_inode(dir);
		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;
	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
 * 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).
 * 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,
static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode,
		       struct nameidata *nd)
		       struct nameidata *nd)
{
{
	dout("create in dir %p dentry %p name '%.*s'\n",
	return ceph_mknod(dir, dentry, mode, 0);
	     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);
}
}


static int ceph_symlink(struct inode *dir, struct dentry *dentry,
static int ceph_symlink(struct inode *dir, struct dentry *dentry,
@@ -1357,6 +1374,7 @@ const struct inode_operations ceph_dir_iops = {
	.rmdir = ceph_unlink,
	.rmdir = ceph_unlink,
	.rename = ceph_rename,
	.rename = ceph_rename,
	.create = ceph_create,
	.create = ceph_create,
	.atomic_open = ceph_atomic_open,
};
};


const struct dentry_operations ceph_dentry_ops = {
const struct dentry_operations ceph_dentry_ops = {
+10 −11
Original line number Original line Diff line number Diff line
@@ -213,21 +213,15 @@ int ceph_open(struct inode *inode, struct file *file)
 * may_open() fails, the struct *file gets cleaned up (i.e.
 * may_open() fails, the struct *file gets cleaned up (i.e.
 * ceph_release gets called).  So fear not!
 * ceph_release gets called).  So fear not!
 */
 */
/*
struct file *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
 * flags
			      struct opendata *od, unsigned flags, umode_t mode)
 *  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 ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
	struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
	struct ceph_mds_client *mdsc = fsc->mdsc;
	struct ceph_mds_client *mdsc = fsc->mdsc;
	struct file *file;
	struct file *file = NULL;
	struct ceph_mds_request *req;
	struct ceph_mds_request *req;
	struct dentry *ret;
	struct dentry *ret;
	int err;
	int err;
	int flags = nd->intent.open.flags;


	dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n",
	dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n",
	     dentry, dentry->d_name.len, dentry->d_name.name, flags, mode);
	     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);
		err = ceph_handle_notrace_create(dir, dentry);
	if (err)
	if (err)
		goto out;
		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))
	if (IS_ERR(file))
		err = PTR_ERR(file);
		err = PTR_ERR(file);
out:
out:
	ret = ceph_finish_lookup(req, dentry, err);
	ret = ceph_finish_lookup(req, dentry, err);
	ceph_mdsc_put_request(req);
	ceph_mdsc_put_request(req);
	dout("ceph_lookup_open result=%p\n", ret);
	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)
int ceph_release(struct inode *inode, struct file *file)
+3 −2
Original line number Original line Diff line number Diff line
@@ -806,8 +806,9 @@ extern int ceph_copy_from_page_vector(struct page **pages,
				    loff_t off, size_t len);
				    loff_t off, size_t len);
extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
extern int ceph_open(struct inode *inode, struct file *file);
extern int ceph_open(struct inode *inode, struct file *file);
extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
extern struct file *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
				       struct nameidata *nd, int mode);
				     struct opendata *od, unsigned flags,
				     umode_t mode);
extern int ceph_release(struct inode *inode, struct file *filp);
extern int ceph_release(struct inode *inode, struct file *filp);


/* dir.c */
/* dir.c */