Commit 14e034a6 authored by Luís Henriques's avatar Luís Henriques Committed by Ilya Dryomov
Browse files

ceph: mark directory as non-complete after loading key



When setting a directory's crypt context, ceph_dir_clear_complete()
needs to be called otherwise if it was complete before, any existing
(old) dentry will still be valid.

This patch adds a wrapper around __fscrypt_prepare_readdir() which will
ensure a directory is marked as non-complete if key status changes.

[ xiubli: revise commit title per Milind ]

Signed-off-by: default avatarLuís Henriques <lhenriques@suse.de>
Reviewed-by: default avatarXiubo Li <xiubli@redhat.com>
Reviewed-by: default avatarMilind Changire <mchangir@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent e127e030
Loading
Loading
Loading
Loading
+33 −2
Original line number Diff line number Diff line
@@ -287,8 +287,8 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
	if (fname->name_len > NAME_MAX || fname->ctext_len > NAME_MAX)
		return -EIO;

	ret = __fscrypt_prepare_readdir(fname->dir);
	if (ret)
	ret = ceph_fscrypt_prepare_readdir(fname->dir);
	if (ret < 0)
		return ret;

	/*
@@ -334,3 +334,34 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
	fscrypt_fname_free_buffer(&_tname);
	return ret;
}

/**
 * ceph_fscrypt_prepare_readdir - simple __fscrypt_prepare_readdir() wrapper
 * @dir: directory inode for readdir prep
 *
 * Simple wrapper around __fscrypt_prepare_readdir() that will mark directory as
 * non-complete if this call results in having the directory unlocked.
 *
 * Returns:
 *     1 - if directory was locked and key is now loaded (i.e. dir is unlocked)
 *     0 - if directory is still locked
 *   < 0 - if __fscrypt_prepare_readdir() fails
 */
int ceph_fscrypt_prepare_readdir(struct inode *dir)
{
	bool had_key = fscrypt_has_encryption_key(dir);
	int err;

	if (!IS_ENCRYPTED(dir))
		return 0;

	err = __fscrypt_prepare_readdir(dir);
	if (err)
		return err;
	if (!had_key && fscrypt_has_encryption_key(dir)) {
		/* directory just got unlocked, mark it as not complete */
		ceph_dir_clear_complete(dir);
		return 1;
	}
	return 0;
}
+6 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ static inline void ceph_fname_free_buffer(struct inode *parent,

int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
		      struct fscrypt_str *oname, bool *is_nokey);
int ceph_fscrypt_prepare_readdir(struct inode *dir);

#else /* CONFIG_FS_ENCRYPTION */

@@ -160,6 +161,11 @@ static inline int ceph_fname_to_usr(const struct ceph_fname *fname,
	oname->len = fname->name_len;
	return 0;
}

static inline int ceph_fscrypt_prepare_readdir(struct inode *dir)
{
	return 0;
}
#endif /* CONFIG_FS_ENCRYPTION */

#endif
+4 −4
Original line number Diff line number Diff line
@@ -343,8 +343,8 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
		ctx->pos = 2;
	}

	err = fscrypt_prepare_readdir(inode);
	if (err)
	err = ceph_fscrypt_prepare_readdir(inode);
	if (err < 0)
		return err;

	spin_lock(&ci->i_ceph_lock);
@@ -785,8 +785,8 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
		return ERR_PTR(-ENAMETOOLONG);

	if (IS_ENCRYPTED(dir)) {
		err = __fscrypt_prepare_readdir(dir);
		if (err)
		err = ceph_fscrypt_prepare_readdir(dir);
		if (err < 0)
			return ERR_PTR(err);
		if (!fscrypt_has_encryption_key(dir)) {
			spin_lock(&dentry->d_lock);
+3 −3
Original line number Diff line number Diff line
@@ -2545,8 +2545,8 @@ static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen)
	if (!IS_ENCRYPTED(dir))
		goto success;

	ret = __fscrypt_prepare_readdir(dir);
	if (ret)
	ret = ceph_fscrypt_prepare_readdir(dir);
	if (ret < 0)
		return ERR_PTR(ret);

	/* No key? Just ignore it. */
@@ -2666,7 +2666,7 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *pbase,
			spin_unlock(&cur->d_lock);
			parent = dget_parent(cur);

			ret = __fscrypt_prepare_readdir(d_inode(parent));
			ret = ceph_fscrypt_prepare_readdir(d_inode(parent));
			if (ret < 0) {
				dput(parent);
				dput(cur);