Commit 7ba2090c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ceph-for-6.6-rc1' of https://github.com/ceph/ceph-client

Pull ceph updates from Ilya Dryomov:
 "Mixed with some fixes and cleanups, this brings in reasonably complete
  fscrypt support to CephFS! The list of things which don't work with
  encryption should be fairly short, mostly around the edges: fallocate
  (not supported well in CephFS to begin with), copy_file_range
  (requires re-encryption), non-default striping patterns.

  This was a multi-year effort principally by Jeff Layton with
  assistance from Xiubo Li, Luís Henriques and others, including several
  dependant changes in the MDS, netfs helper library and fscrypt
  framework itself"

* tag 'ceph-for-6.6-rc1' of https://github.com/ceph/ceph-client: (53 commits)
  ceph: make num_fwd and num_retry to __u32
  ceph: make members in struct ceph_mds_request_args_ext a union
  rbd: use list_for_each_entry() helper
  libceph: do not include crypto/algapi.h
  ceph: switch ceph_lookup/atomic_open() to use new fscrypt helper
  ceph: fix updating i_truncate_pagecache_size for fscrypt
  ceph: wait for OSD requests' callbacks to finish when unmounting
  ceph: drop messages from MDS when unmounting
  ceph: update documentation regarding snapshot naming limitations
  ceph: prevent snapshot creation in encrypted locked directories
  ceph: add support for encrypted snapshot names
  ceph: invalidate pages when doing direct/sync writes
  ceph: plumb in decryption during reads
  ceph: add encryption support to writepage and writepages
  ceph: add read/modify/write to ceph_sync_write
  ceph: align data in pages in ceph_sync_write
  ceph: don't use special DIO path for encrypted inodes
  ceph: add truncate size handling support for fscrypt
  ceph: add object version support for sync read
  libceph: allow ceph_osdc_new_request to accept a multi-op read
  ...
parents 744a7594 ce0d5bd3
......@@ -57,6 +57,16 @@ a snapshot on any subdirectory (and its nested contents) in the
system. Snapshot creation and deletion are as simple as 'mkdir
.snap/foo' and 'rmdir .snap/foo'.
Snapshot names have two limitations:
* They can not start with an underscore ('_'), as these names are reserved
for internal usage by the MDS.
* They can not exceed 240 characters in size. This is because the MDS makes
use of long snapshot names internally, which follow the format:
`_<SNAPSHOT-NAME>_<INODE-NUMBER>`. Since filenames in general can't have
more than 255 characters, and `<node-id>` takes 13 characters, the long
snapshot names can take as much as 255 - 1 - 1 - 13 = 240.
Ceph also provides some recursive accounting on directories for nested
files and bytes. That is, a 'getfattr -d foo' on any directory in the
system will reveal the total number of nested regular files and
......
......@@ -7199,7 +7199,6 @@ static void rbd_dev_remove_parent(struct rbd_device *rbd_dev)
static ssize_t do_rbd_remove(const char *buf, size_t count)
{
struct rbd_device *rbd_dev = NULL;
struct list_head *tmp;
int dev_id;
char opt_buf[6];
bool force = false;
......@@ -7226,8 +7225,7 @@ static ssize_t do_rbd_remove(const char *buf, size_t count)
ret = -ENOENT;
spin_lock(&rbd_dev_list_lock);
list_for_each(tmp, &rbd_dev_list) {
rbd_dev = list_entry(tmp, struct rbd_device, node);
list_for_each_entry(rbd_dev, &rbd_dev_list, node) {
if (rbd_dev->dev_id == dev_id) {
ret = 0;
break;
......
......@@ -12,3 +12,4 @@ ceph-y := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \
ceph-$(CONFIG_CEPH_FSCACHE) += cache.o
ceph-$(CONFIG_CEPH_FS_POSIX_ACL) += acl.o
ceph-$(CONFIG_FS_ENCRYPTION) += crypto.o
......@@ -140,7 +140,7 @@ int ceph_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
newattrs.ia_ctime = current_time(inode);
newattrs.ia_mode = new_mode;
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
ret = __ceph_setattr(inode, &newattrs);
ret = __ceph_setattr(inode, &newattrs, NULL);
if (ret)
goto out_free;
}
......@@ -151,7 +151,7 @@ int ceph_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
newattrs.ia_ctime = old_ctime;
newattrs.ia_mode = old_mode;
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
__ceph_setattr(inode, &newattrs);
__ceph_setattr(inode, &newattrs, NULL);
}
goto out_free;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Ceph fscrypt functionality
*/
#ifndef _CEPH_CRYPTO_H
#define _CEPH_CRYPTO_H
#include <crypto/sha2.h>
#include <linux/fscrypt.h>
#define CEPH_FSCRYPT_BLOCK_SHIFT 12
#define CEPH_FSCRYPT_BLOCK_SIZE (_AC(1, UL) << CEPH_FSCRYPT_BLOCK_SHIFT)
#define CEPH_FSCRYPT_BLOCK_MASK (~(CEPH_FSCRYPT_BLOCK_SIZE-1))
struct ceph_fs_client;
struct ceph_acl_sec_ctx;
struct ceph_mds_request;
struct ceph_fname {
struct inode *dir;
char *name; // b64 encoded, possibly hashed
unsigned char *ctext; // binary crypttext (if any)
u32 name_len; // length of name buffer
u32 ctext_len; // length of crypttext
bool no_copy;
};
/*
* Header for the crypted file when truncating the size, this
* will be sent to MDS, and the MDS will update the encrypted
* last block and then truncate the size.
*/
struct ceph_fscrypt_truncate_size_header {
__u8 ver;
__u8 compat;
/*
* It will be sizeof(assert_ver + file_offset + block_size)
* if the last block is empty when it's located in a file
* hole. Or the data_len will plus CEPH_FSCRYPT_BLOCK_SIZE.
*/
__le32 data_len;
__le64 change_attr;
__le64 file_offset;
__le32 block_size;
} __packed;
struct ceph_fscrypt_auth {
__le32 cfa_version;
__le32 cfa_blob_len;
u8 cfa_blob[FSCRYPT_SET_CONTEXT_MAX_SIZE];
} __packed;
#define CEPH_FSCRYPT_AUTH_VERSION 1
static inline u32 ceph_fscrypt_auth_len(struct ceph_fscrypt_auth *fa)
{
u32 ctxsize = le32_to_cpu(fa->cfa_blob_len);
return offsetof(struct ceph_fscrypt_auth, cfa_blob) + ctxsize;
}
#ifdef CONFIG_FS_ENCRYPTION
/*
* We want to encrypt filenames when creating them, but the encrypted
* versions of those names may have illegal characters in them. To mitigate
* that, we base64 encode them, but that gives us a result that can exceed
* NAME_MAX.
*
* Follow a similar scheme to fscrypt itself, and cap the filename to a
* smaller size. If the ciphertext name is longer than the value below, then
* sha256 hash the remaining bytes.
*
* For the fscrypt_nokey_name struct the dirhash[2] member is useless in ceph
* so the corresponding struct will be:
*
* struct fscrypt_ceph_nokey_name {
* u8 bytes[157];
* u8 sha256[SHA256_DIGEST_SIZE];
* }; // 180 bytes => 240 bytes base64-encoded, which is <= NAME_MAX (255)
*
* (240 bytes is the maximum size allowed for snapshot names to take into
* account the format: '_<SNAPSHOT-NAME>_<INODE-NUMBER>'.)
*
* Note that for long names that end up having their tail portion hashed, we
* must also store the full encrypted name (in the dentry's alternate_name
* field).
*/
#define CEPH_NOHASH_NAME_MAX (180 - SHA256_DIGEST_SIZE)
#define CEPH_BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
int ceph_base64_encode(const u8 *src, int srclen, char *dst);
int ceph_base64_decode(const char *src, int srclen, u8 *dst);
void ceph_fscrypt_set_ops(struct super_block *sb);
void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc);
int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode,
struct ceph_acl_sec_ctx *as);
void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
struct ceph_acl_sec_ctx *as);
int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
char *buf);
int ceph_encode_encrypted_fname(struct inode *parent, struct dentry *dentry,
char *buf);
static inline int ceph_fname_alloc_buffer(struct inode *parent,
struct fscrypt_str *fname)
{
if (!IS_ENCRYPTED(parent))
return 0;
return fscrypt_fname_alloc_buffer(NAME_MAX, fname);
}
static inline void ceph_fname_free_buffer(struct inode *parent,
struct fscrypt_str *fname)
{
if (IS_ENCRYPTED(parent))
fscrypt_fname_free_buffer(fname);
}
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);
static inline unsigned int ceph_fscrypt_blocks(u64 off, u64 len)
{
/* crypto blocks cannot span more than one page */
BUILD_BUG_ON(CEPH_FSCRYPT_BLOCK_SHIFT > PAGE_SHIFT);
return ((off+len+CEPH_FSCRYPT_BLOCK_SIZE-1) >> CEPH_FSCRYPT_BLOCK_SHIFT) -
(off >> CEPH_FSCRYPT_BLOCK_SHIFT);
}
/*
* If we have an encrypted inode then we must adjust the offset and
* range of the on-the-wire read to cover an entire encryption block.
* The copy will be done using the original offset and length, after
* we've decrypted the result.
*/
static inline void ceph_fscrypt_adjust_off_and_len(struct inode *inode,
u64 *off, u64 *len)
{
if (IS_ENCRYPTED(inode)) {
*len = ceph_fscrypt_blocks(*off, *len) * CEPH_FSCRYPT_BLOCK_SIZE;
*off &= CEPH_FSCRYPT_BLOCK_MASK;
}
}
int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode,
struct page *page, unsigned int len,
unsigned int offs, u64 lblk_num);
int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode,
struct page *page, unsigned int len,
unsigned int offs, u64 lblk_num,
gfp_t gfp_flags);
int ceph_fscrypt_decrypt_pages(struct inode *inode, struct page **page,
u64 off, int len);
int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page,
u64 off, struct ceph_sparse_extent *map,
u32 ext_cnt);
int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off,
int len, gfp_t gfp);
static inline struct page *ceph_fscrypt_pagecache_page(struct page *page)
{
return fscrypt_is_bounce_page(page) ? fscrypt_pagecache_page(page) : page;
}
#else /* CONFIG_FS_ENCRYPTION */
static inline void ceph_fscrypt_set_ops(struct super_block *sb)
{
}
static inline void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc)
{
}
static inline int ceph_fscrypt_prepare_context(struct inode *dir,
struct inode *inode,
struct ceph_acl_sec_ctx *as)
{
if (IS_ENCRYPTED(dir))
return -EOPNOTSUPP;
return 0;
}
static inline void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
struct ceph_acl_sec_ctx *as_ctx)
{
}
static inline int ceph_encode_encrypted_dname(struct inode *parent,
struct qstr *d_name, char *buf)
{
memcpy(buf, d_name->name, d_name->len);
return d_name->len;
}
static inline int ceph_encode_encrypted_fname(struct inode *parent,
struct dentry *dentry, char *buf)
{
return -EOPNOTSUPP;
}
static inline int ceph_fname_alloc_buffer(struct inode *parent,
struct fscrypt_str *fname)
{
return 0;
}
static inline void ceph_fname_free_buffer(struct inode *parent,
struct fscrypt_str *fname)
{
}
static inline int ceph_fname_to_usr(const struct ceph_fname *fname,
struct fscrypt_str *tname,
struct fscrypt_str *oname, bool *is_nokey)
{
oname->name = fname->name;
oname->len = fname->name_len;
return 0;
}
static inline int ceph_fscrypt_prepare_readdir(struct inode *dir)
{
return 0;
}
static inline void ceph_fscrypt_adjust_off_and_len(struct inode *inode,
u64 *off, u64 *len)
{
}
static inline int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode,
struct page *page, unsigned int len,
unsigned int offs, u64 lblk_num)
{
return 0;
}
static inline int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode,
struct page *page, unsigned int len,
unsigned int offs, u64 lblk_num,
gfp_t gfp_flags)
{
return 0;
}
static inline int ceph_fscrypt_decrypt_pages(struct inode *inode,
struct page **page, u64 off,
int len)
{
return 0;
}
static inline int ceph_fscrypt_decrypt_extents(struct inode *inode,
struct page **page, u64 off,
struct ceph_sparse_extent *map,
u32 ext_cnt)
{
return 0;
}
static inline int ceph_fscrypt_encrypt_pages(struct inode *inode,
struct page **page, u64 off,
int len, gfp_t gfp)
{
return 0;
}
static inline struct page *ceph_fscrypt_pagecache_page(struct page *page)
{
return page;
}
#endif /* CONFIG_FS_ENCRYPTION */
static inline loff_t ceph_fscrypt_page_offset(struct page *page)
{
return page_offset(ceph_fscrypt_pagecache_page(page));
}
#endif /* _CEPH_CRYPTO_H */
This diff is collapsed.
......@@ -7,6 +7,7 @@
#include "super.h"
#include "mds_client.h"
#include "crypto.h"
/*
* Basic fh
......@@ -535,7 +536,9 @@ static int ceph_get_name(struct dentry *parent, char *name,
{
struct ceph_mds_client *mdsc;
struct ceph_mds_request *req;
struct inode *dir = d_inode(parent);
struct inode *inode = d_inode(child);
struct ceph_mds_reply_info_parsed *rinfo;
int err;
if (ceph_snap(inode) != CEPH_NOSNAP)
......@@ -547,30 +550,47 @@ static int ceph_get_name(struct dentry *parent, char *name,
if (IS_ERR(req))
return PTR_ERR(req);
inode_lock(d_inode(parent));
inode_lock(dir);
req->r_inode = inode;
ihold(inode);
req->r_ino2 = ceph_vino(d_inode(parent));
req->r_parent = d_inode(parent);
ihold(req->r_parent);
req->r_parent = dir;
ihold(dir);
set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
req->r_num_caps = 2;
err = ceph_mdsc_do_request(mdsc, NULL, req);
inode_unlock(dir);
inode_unlock(d_inode(parent));
if (err)
goto out;
if (!err) {
struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
rinfo = &req->r_reply_info;
if (!IS_ENCRYPTED(dir)) {
memcpy(name, rinfo->dname, rinfo->dname_len);
name[rinfo->dname_len] = 0;
dout("get_name %p ino %llx.%llx name %s\n",
child, ceph_vinop(inode), name);
} else {
dout("get_name %p ino %llx.%llx err %d\n",
child, ceph_vinop(inode), err);
}
struct fscrypt_str oname = FSTR_INIT(NULL, 0);
struct ceph_fname fname = { .dir = dir,
.name = rinfo->dname,
.ctext = rinfo->altname,
.name_len = rinfo->dname_len,
.ctext_len = rinfo->altname_len };
err = ceph_fname_alloc_buffer(dir, &oname);
if (err < 0)
goto out;
err = ceph_fname_to_usr(&fname, NULL, &oname, NULL);
if (!err) {
memcpy(name, oname.name, oname.len);
name[oname.len] = 0;
}
ceph_fname_free_buffer(dir, &oname);
}
out:
dout("get_name %p ino %llx.%llx err %d %s%s\n",
child, ceph_vinop(inode), err,
err ? "" : "name ", err ? "" : name);
ceph_mdsc_put_request(req);
return err;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -6,6 +6,7 @@
#include "mds_client.h"
#include "ioctl.h"
#include <linux/ceph/striper.h>
#include <linux/fscrypt.h>
/*
* ioctls
......@@ -268,9 +269,96 @@ static long ceph_ioctl_syncio(struct file *file)
return 0;
}
static int vet_mds_for_fscrypt(struct file *file)
{
int i, ret = -EOPNOTSUPP;
struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(file_inode(file)->i_sb);
mutex_lock(&mdsc->mutex);
for (i = 0; i < mdsc->max_sessions; i++) {
struct ceph_mds_session *s = mdsc->sessions[i];
if (!s)
continue;
if (test_bit(CEPHFS_FEATURE_ALTERNATE_NAME, &s->s_features))
ret = 0;
break;
}
mutex_unlock(&mdsc->mutex);
return ret;
}
static long ceph_set_encryption_policy(struct file *file, unsigned long arg)
{
int ret, got = 0;
struct inode *inode = file_inode(file);
struct ceph_inode_info *ci = ceph_inode(inode);
/* encrypted directories can't have striped layout */
if (ci->i_layout.stripe_count > 1)
return -EINVAL;
ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;
/*
* Ensure we hold these caps so that we _know_ that the rstats check
* in the empty_dir check is reliable.
*/
ret = ceph_get_caps(file, CEPH_CAP_FILE_SHARED, 0, -1, &got);
if (ret)
return ret;
ret = fscrypt_ioctl_set_policy(file, (const void __user *)arg);
if (got)
ceph_put_cap_refs(ci, got);
return ret;
}
static const char *ceph_ioctl_cmd_name(const unsigned int cmd)
{
switch (cmd) {
case CEPH_IOC_GET_LAYOUT:
return "get_layout";
case CEPH_IOC_SET_LAYOUT:
return "set_layout";
case CEPH_IOC_SET_LAYOUT_POLICY:
return "set_layout_policy";
case CEPH_IOC_GET_DATALOC:
return "get_dataloc";
case CEPH_IOC_LAZYIO:
return "lazyio";
case CEPH_IOC_SYNCIO:
return "syncio";
case FS_IOC_SET_ENCRYPTION_POLICY:
return "set_encryption_policy";
case FS_IOC_GET_ENCRYPTION_POLICY:
return "get_encryption_policy";
case FS_IOC_GET_ENCRYPTION_POLICY_EX:
return "get_encryption_policy_ex";
case FS_IOC_ADD_ENCRYPTION_KEY:
return "add_encryption_key";
case FS_IOC_REMOVE_ENCRYPTION_KEY:
return "remove_encryption_key";
case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
return "remove_encryption_key_all_users";
case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
return "get_encryption_key_status";
case FS_IOC_GET_ENCRYPTION_NONCE:
return "get_encryption_nonce";
default:
return "unknown";
}
}
long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
int ret;
dout("ioctl file %p cmd %s arg %lu\n", file,
ceph_ioctl_cmd_name(cmd), arg);
switch (cmd) {
case CEPH_IOC_GET_LAYOUT:
return ceph_ioctl_get_layout(file, (void __user *)arg);
......@@ -289,6 +377,43 @@ long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case CEPH_IOC_SYNCIO:
return ceph_ioctl_syncio(file);
case FS_IOC_SET_ENCRYPTION_POLICY:
return ceph_set_encryption_policy(file, arg);
case FS_IOC_GET_ENCRYPTION_POLICY:
ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;
return fscrypt_ioctl_get_policy(file, (void __user *)arg);
case FS_IOC_GET_ENCRYPTION_POLICY_EX:
ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;
return fscrypt_ioctl_get_policy_ex(file, (void __user *)arg);
case FS_IOC_ADD_ENCRYPTION_KEY:
ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;
return fscrypt_ioctl_add_key(file, (void __user *)arg);
case FS_IOC_REMOVE_ENCRYPTION_KEY:
return fscrypt_ioctl_remove_key(file, (void __user *)arg);
case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
return fscrypt_ioctl_remove_key_all_users(file,
(void __user *)arg);
case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
return fscrypt_ioctl_get_key_status(file, (void __user *)arg);
case FS_IOC_GET_ENCRYPTION_NONCE:
ret = vet_mds_for_fscrypt(file);
if (ret)
return ret;
return fscrypt_ioctl_get_nonce(file, (void __user *)arg);
}
return -ENOTTY;
......
This diff is collapsed.
......@@ -32,8 +32,9 @@ enum ceph_feature_type {
CEPHFS_FEATURE_ALTERNATE_NAME,
CEPHFS_FEATURE_NOTIFY_SESSION_STATE,
CEPHFS_FEATURE_OP_GETVXATTR,
CEPHFS_FEATURE_32BITS_RETRY_FWD,
CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_OP_GETVXATTR,
CEPHFS_FEATURE_MAX = CEPHFS_FEATURE_32BITS_RETRY_FWD,
};
#define CEPHFS_FEATURES_CLIENT_SUPPORTED { \
......@@ -44,8 +45,10 @@ enum ceph_feature_type {
CEPHFS_FEATURE_MULTI_RECONNECT, \
CEPHFS_FEATURE_DELEG_INO, \
CEPHFS_FEATURE_METRIC_COLLECT, \
CEPHFS_FEATURE_ALTERNATE_NAME, \
CEPHFS_FEATURE_NOTIFY_SESSION_STATE, \
CEPHFS_FEATURE_OP_GETVXATTR, \
CEPHFS_FEATURE_32BITS_RETRY_FWD, \
}
/*
......@@ -86,13 +89,19 @@ struct ceph_mds_reply_info_in {
s32 dir_pin;
struct ceph_timespec btime;
struct ceph_timespec snap_btime;
u8 *fscrypt_auth;
u8 *fscrypt_file;
u32 fscrypt_auth_len;
u32 fscrypt_file_len;
u64 rsnaps;
u64 change_attr;
};
struct ceph_mds_reply_dir_entry {
bool is_nokey;
char *name;
u32 name_len;
u32 raw_hash;
struct ceph_mds_reply_lease *lease;
struct ceph_mds_reply_info_in inode;
loff_t offset;
......@@ -116,7 +125,9 @@ struct ceph_mds_reply_info_parsed {
struct ceph_mds_reply_info_in diri, targeti;
struct ceph_mds_reply_dirfrag *dirfrag;
char *dname;
u8 *altname;
u32 dname_len;
u32 altname_len;
struct ceph_mds_reply_lease *dlease;
struct ceph_mds_reply_xattr xattr_info;
......@@ -263,6 +274,7 @@ struct ceph_mds_request {
struct inode *r_parent; /* parent dir inode */
struct inode *r_target_inode; /* resulting inode */
struct inode *r_new_inode; /* new inode (for creates) */
#define CEPH_MDS_R_DIRECT_IS_HASH (1) /* r_direct_hash is valid */
#define CEPH_MDS_R_ABORTED (2) /* call was aborted */
......@@ -272,11 +284,19 @@ struct ceph_mds_request {
#define CEPH_MDS_R_DID_PREPOPULATE (6) /* prepopulated readdir */
#define CEPH_MDS_R_PARENT_LOCKED (7) /* is r_parent->i_rwsem wlocked? */
#define CEPH_MDS_R_ASYNC (8) /* async request */
#define CEPH_MDS_R_FSCRYPT_FILE (9) /* must marshal fscrypt_file field */
unsigned long r_req_flags;
struct mutex r_fill_mutex;
union ceph_mds_request_args r_args;
struct ceph_fscrypt_auth *r_fscrypt_auth;
u64 r_fscrypt_file;
u8 *r_altname; /* fscrypt binary crypttext for long filenames */
u32 r_altname_len; /* length of r_altname */
int r_fmode; /* file mode, if expecting cap */
int r_request_release_offset;
const struct cred *r_cred;
......@@ -381,8 +401,9 @@ struct cap_wait {
};
enum {
CEPH_MDSC_STOPPING_BEGIN = 1,
CEPH_MDSC_STOPPING_FLUSHED = 2,
CEPH_MDSC_STOPPING_BEGIN = 1,
CEPH_MDSC_STOPPING_FLUSHING = 2,
CEPH_MDSC_STOPPING_FLUSHED = 3,
};
/*
......@@ -401,7 +422,11 @@ struct ceph_mds_client {
struct ceph_mds_session **sessions; /* NULL for mds if no session */
atomic_t num_sessions;
int max_sessions; /* len of sessions array */
int stopping; /* true if shutting down */
spinlock_t stopping_lock; /* protect snap_empty */
int stopping; /* the stage of shutting down */
atomic_t stopping_blockers;
struct completion stopping_waiter;
atomic64_t quotarealms_count; /* # realms with quota */
/*
......@@ -557,7 +582,7 @@ static inline void ceph_mdsc_free_path(char *path, int len)
}
extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
int stop_on_nosnap);
int for_wire);
extern void __ceph_mdsc_drop_dentry_lease(struct dentry *dentry);
extern void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
......
......@@ -47,25 +47,23 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc,
struct inode *inode;
struct ceph_inode_info *ci;
if (!ceph_inc_mds_stopping_blocker(mdsc, session))
return;
if (msg->front.iov_len < sizeof(*h)) {
pr_err("%s corrupt message mds%d len %d\n", __func__,
session->s_mds, (int)msg->front.iov_len);
ceph_msg_dump(msg);
return;
goto out;
}
/* increment msg sequence number */
mutex_lock(&session->s_mutex);
inc_session_sequence(session);
mutex_unlock(&session->s_mutex);
/* lookup inode */
vino.ino = le64_to_cpu(h->ino);
vino.snap = CEPH_NOSNAP;
inode = ceph_find_inode(sb, vino);
if (!inode) {
pr_warn("Failed to find inode %llu\n", vino.ino);
return;
goto out;
}
ci = ceph_inode(inode);
......@@ -78,6 +76,8 @@ void ceph_handle_quota(struct ceph_mds_client *mdsc,
spin_unlock(&ci->i_ceph_lock);
iput(inode);
out:
ceph_dec_mds_stopping_blocker(mdsc);
}
static struct ceph_quotarealm_inode *
......
......@@ -1015,6 +1015,9 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
int locked_rwsem = 0;
bool close_sessions = false;
if (!ceph_inc_mds_stopping_blocker(mdsc, session))
return;
/* decode */
if (msg->front.iov_len < sizeof(*h))
goto bad;
......@@ -1030,10 +1033,6 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
dout("%s from mds%d op %s split %llx tracelen %d\n", __func__,
mds, ceph_snap_op_name(op), split, trace_len);
mutex_lock(&session->s_mutex);
inc_session_sequence(session);
mutex_unlock(&session->s_mutex);
down_write(&mdsc->snap_rwsem);
locked_rwsem = 1;
......@@ -1151,6 +1150,7 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
up_write(&mdsc->snap_rwsem);
flush_snaps(mdsc);
ceph_dec_mds_stopping_blocker(mdsc);
return;
bad:
......@@ -1160,6 +1160,8 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
if (locked_rwsem)
up_write(&mdsc->snap_rwsem);
ceph_dec_mds_stopping_blocker(mdsc);
if (close_sessions)
ceph_mdsc_close_sessions(mdsc);
return;
......
......@@ -20,6 +20,7 @@
#include "super.h"
#include "mds_client.h"
#include "cache.h"
#include "crypto.h"
#include <linux/ceph/ceph_features.h>
#include <linux/ceph/decode.h>
......@@ -46,6 +47,7 @@ static void ceph_put_super(struct super_block *s)
struct ceph_fs_client *fsc = ceph_sb_to_client(s);
dout("put_super\n");
ceph_fscrypt_free_dummy_policy(fsc);
ceph_mdsc_close_sessions(fsc->mdsc);
}
......@@ -151,6 +153,7 @@ enum {
Opt_recover_session,
Opt_source,
Opt_mon_addr,
Opt_test_dummy_encryption,
/* string args above */
Opt_dirstat,
Opt_rbytes,
......@@ -165,6 +168,7 @@ enum {
Opt_copyfrom,
Opt_wsync,
Opt_pagecache,
Opt_sparseread,
};
enum ceph_recover_session_mode {
......@@ -192,6 +196,7 @@ static const struct fs_parameter_spec ceph_mount_parameters[] = {
fsparam_string ("fsc", Opt_fscache), // fsc=...
fsparam_flag_no ("ino32", Opt_ino32),
fsparam_string ("mds_namespace", Opt_mds_namespace),
fsparam_string ("mon_addr", Opt_mon_addr),
fsparam_flag_no ("poolperm", Opt_poolperm),
fsparam_flag_no ("quotadf", Opt_quotadf),
fsparam_u32 ("rasize", Opt_rasize),
......@@ -203,10 +208,12 @@ static const struct fs_parameter_spec ceph_mount_parameters[] = {
fsparam_u32 ("rsize", Opt_rsize),
fsparam_string ("snapdirname", Opt_snapdirname),
fsparam_string ("source", Opt_source),
fsparam_string ("mon_addr", Opt_mon_addr),
fsparam_flag ("test_dummy_encryption", Opt_test_dummy_encryption),
fsparam_string ("test_dummy_encryption", Opt_test_dummy_encryption),
fsparam_u32 ("wsize", Opt_wsize),
fsparam_flag_no ("wsync", Opt_wsync),
fsparam_flag_no ("pagecache", Opt_pagecache),
fsparam_flag_no ("sparseread", Opt_sparseread),
{}
};
......@@ -576,6 +583,29 @@ static int ceph_parse_mount_param(struct fs_context *fc,
else
fsopt->flags &= ~CEPH_MOUNT_OPT_NOPAGECACHE;
break;
case Opt_sparseread:
if (result.negated)
fsopt->flags &= ~CEPH_MOUNT_OPT_SPARSEREAD;
else
fsopt->flags |= CEPH_MOUNT_OPT_SPARSEREAD;
break;
case Opt_test_dummy_encryption:
#ifdef CONFIG_FS_ENCRYPTION
fscrypt_free_dummy_policy(&fsopt->dummy_enc_policy);
ret = fscrypt_parse_test_dummy_encryption(param,
&fsopt->dummy_enc_policy);
if (ret == -EINVAL) {
warnfc(fc, "Value of option \"%s\" is unrecognized",
param->key);
} else if (ret == -EEXIST) {
warnfc(fc, "Conflicting test_dummy_encryption options");
ret = -EINVAL;
}
#else
warnfc(fc,
"FS encryption not supported: test_dummy_encryption mount option ignored");
#endif
break;
default:
BUG();
}
......@@ -596,6 +626,7 @@ static void destroy_mount_options(struct ceph_mount_options *args)
kfree(args->server_path);
kfree(args->fscache_uniq);
kfree(args->mon_addr);
fscrypt_free_dummy_policy(&args->dummy_enc_policy);
kfree(args);
}
......@@ -710,9 +741,12 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
if (!(fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS))
seq_puts(m, ",wsync");
if (fsopt->flags & CEPH_MOUNT_OPT_NOPAGECACHE)
seq_puts(m, ",nopagecache");
if (fsopt->flags & CEPH_MOUNT_OPT_SPARSEREAD)
seq_puts(m, ",sparseread");
fscrypt_show_test_dummy_encryption(m, ',', root->d_sb);
if (fsopt->wsize != CEPH_MAX_WRITE_SIZE)
seq_printf(m, ",wsize=%u", fsopt->wsize);
......@@ -1052,6 +1086,50 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
return root;
}
#ifdef CONFIG_FS_ENCRYPTION
static int ceph_apply_test_dummy_encryption(struct super_block *sb,
struct fs_context *fc,
struct ceph_mount_options *fsopt)
{
struct ceph_fs_client *fsc = sb->s_fs_info;
if (!fscrypt_is_dummy_policy_set(&fsopt->dummy_enc_policy))
return 0;
/* No changing encryption context on remount. */
if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE &&
!fscrypt_is_dummy_policy_set(&fsc->fsc_dummy_enc_policy)) {
if (fscrypt_dummy_policies_equal(&fsopt->dummy_enc_policy,
&fsc->fsc_dummy_enc_policy))
return 0;
errorfc(fc, "Can't set test_dummy_encryption on remount");
return -EINVAL;
}
/* Also make sure fsopt doesn't contain a conflicting value. */
if (fscrypt_is_dummy_policy_set(&fsc->fsc_dummy_enc_policy)) {
if (fscrypt_dummy_policies_equal(&fsopt->dummy_enc_policy,
&fsc->fsc_dummy_enc_policy))
return 0;
errorfc(fc, "Conflicting test_dummy_encryption options");
return -EINVAL;
}
fsc->fsc_dummy_enc_policy = fsopt->dummy_enc_policy;
memset(&fsopt->dummy_enc_policy, 0, sizeof(fsopt->dummy_enc_policy));
warnfc(fc, "test_dummy_encryption mode enabled");
return 0;
}
#else
static int ceph_apply_test_dummy_encryption(struct super_block *sb,
struct fs_context *fc,
struct ceph_mount_options *fsopt)
{
return 0;
}
#endif
/*
* mount: join the ceph cluster, and open root directory.
*/
......@@ -1080,6 +1158,11 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
goto out;
}
err = ceph_apply_test_dummy_encryption(fsc->sb, fc,
fsc->mount_options);
if (err)
goto out;
dout("mount opening path '%s'\n", path);
ceph_fs_debugfs_init(fsc);
......@@ -1101,6 +1184,7 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
out:
mutex_unlock(&fsc->client->mount_mutex);
ceph_fscrypt_free_dummy_policy(fsc);
return ERR_PTR(err);
}
......@@ -1126,6 +1210,8 @@ static int ceph_set_super(struct super_block *s, struct fs_context *fc)
s->s_time_max = U32_MAX;
s->s_flags |= SB_NODIRATIME | SB_NOATIME;
ceph_fscrypt_set_ops(s);
ret = set_anon_super_fc(s, fc);
if (ret != 0)
fsc->sb = NULL;
......@@ -1287,15 +1373,26 @@ static void ceph_free_fc(struct fs_context *fc)
static int ceph_reconfigure_fc(struct fs_context *fc)
{
int err;
struct ceph_parse_opts_ctx *pctx = fc->fs_private;
struct ceph_mount_options *fsopt = pctx->opts;
struct ceph_fs_client *fsc = ceph_sb_to_client(fc->root->d_sb);
struct super_block *sb = fc->root->d_sb;
struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
err = ceph_apply_test_dummy_encryption(sb, fc, fsopt);
if (err)
return err;
if (fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS)
ceph_set_mount_opt(fsc, ASYNC_DIROPS);
else
ceph_clear_mount_opt(fsc, ASYNC_DIROPS);
if (fsopt->flags & CEPH_MOUNT_OPT_SPARSEREAD)
ceph_set_mount_opt(fsc, SPARSEREAD);
else
ceph_clear_mount_opt(fsc, SPARSEREAD);
if (strcmp_null(fsc->mount_options->mon_addr, fsopt->mon_addr)) {
kfree(fsc->mount_options->mon_addr);
fsc->mount_options->mon_addr = fsopt->mon_addr;
......@@ -1303,7 +1400,7 @@ static int ceph_reconfigure_fc(struct fs_context *fc)
pr_notice("ceph: monitor addresses recorded, but not used for reconnection");
}
sync_filesystem(fc->root->d_sb);
sync_filesystem(sb);
return 0;
}
......@@ -1365,25 +1462,101 @@ static int ceph_init_fs_context(struct fs_context *fc)
return -ENOMEM;
}
/*
* Return true if it successfully increases the blocker counter,
* or false if the mdsc is in stopping and flushed state.
*/
static bool __inc_stopping_blocker(struct ceph_mds_client *mdsc)
{
spin_lock(&mdsc->stopping_lock);
if (mdsc->stopping >= CEPH_MDSC_STOPPING_FLUSHING) {
spin_unlock(&mdsc->stopping_lock);
return false;
}
atomic_inc(&mdsc->stopping_blockers);
spin_unlock(&mdsc->stopping_lock);
return true;
}
static void __dec_stopping_blocker(struct ceph_mds_client *mdsc)
{
spin_lock(&mdsc->stopping_lock);
if (!atomic_dec_return(&mdsc->stopping_blockers) &&
mdsc->stopping >= CEPH_MDSC_STOPPING_FLUSHING)
complete_all(&mdsc->stopping_waiter);
spin_unlock(&mdsc->stopping_lock);
}
/* For metadata IO requests */
bool ceph_inc_mds_stopping_blocker(struct ceph_mds_client *mdsc,
struct ceph_mds_session *session)
{
mutex_lock(&session->s_mutex);
inc_session_sequence(session);
mutex_unlock(&session->s_mutex);
return __inc_stopping_blocker(mdsc);
}
void ceph_dec_mds_stopping_blocker(struct ceph_mds_client *mdsc)
{
__dec_stopping_blocker(mdsc);
}
/* For data IO requests */
bool ceph_inc_osd_stopping_blocker(struct ceph_mds_client *mdsc)
{
return __inc_stopping_blocker(mdsc);
}
void ceph_dec_osd_stopping_blocker(struct ceph_mds_client *mdsc)
{
__dec_stopping_blocker(mdsc);
}
static void ceph_kill_sb(struct super_block *s)
{
struct ceph_fs_client *fsc = ceph_sb_to_client(s);
struct ceph_mds_client *mdsc = fsc->mdsc;
bool wait;
dout("kill_sb %p\n", s);
ceph_mdsc_pre_umount(fsc->mdsc);
ceph_mdsc_pre_umount(mdsc);
flush_fs_workqueues(fsc);
/*
* Though the kill_anon_super() will finally trigger the
* sync_filesystem() anyway, we still need to do it here
* and then bump the stage of shutdown to stop the work
* queue as earlier as possible.
* sync_filesystem() anyway, we still need to do it here and
* then bump the stage of shutdown. This will allow us to
* drop any further message, which will increase the inodes'
* i_count reference counters but makes no sense any more,
* from MDSs.
*
* Without this when evicting the inodes it may fail in the
* kill_anon_super(), which will trigger a warning when
* destroying the fscrypt keyring and then possibly trigger
* a further crash in ceph module when the iput() tries to
* evict the inodes later.
*/
sync_filesystem(s);
fsc->mdsc->stopping = CEPH_MDSC_STOPPING_FLUSHED;
spin_lock(&mdsc->stopping_lock);
mdsc->stopping = CEPH_MDSC_STOPPING_FLUSHING;
wait = !!atomic_read(&mdsc->stopping_blockers);
spin_unlock(&mdsc->stopping_lock);
if (wait && atomic_read(&mdsc->stopping_blockers)) {
long timeleft = wait_for_completion_killable_timeout(
&mdsc->stopping_waiter,
fsc->client->options->mount_timeout);
if (!timeleft) /* timed out */
pr_warn("umount timed out, %ld\n", timeleft);
else if (timeleft < 0) /* killed */
pr_warn("umount was killed, %ld\n", timeleft);
}
mdsc->stopping = CEPH_MDSC_STOPPING_FLUSHED;
kill_anon_super(s);
fsc->client->extra_mon_dispatch = NULL;
......
......@@ -22,6 +22,7 @@
#include <linux/hashtable.h>
#include <linux/ceph/libceph.h>
#include "crypto.h"
/* large granularity for statfs utilization stats to facilitate
* large volume sizes on 32-bit machines. */
......@@ -42,6 +43,7 @@
#define CEPH_MOUNT_OPT_NOCOPYFROM (1<<14) /* don't use RADOS 'copy-from' op */
#define CEPH_MOUNT_OPT_ASYNC_DIROPS (1<<15) /* allow async directory ops */
#define CEPH_MOUNT_OPT_NOPAGECACHE (1<<16) /* bypass pagecache altogether */
#define CEPH_MOUNT_OPT_SPARSEREAD (1<<17) /* always do sparse reads */
#define CEPH_MOUNT_OPT_DEFAULT \
(CEPH_MOUNT_OPT_DCACHE | \
......@@ -98,6 +100,7 @@ struct ceph_mount_options {
char *server_path; /* default NULL (means "/") */
char *fscache_uniq; /* default NULL */
char *mon_addr;
struct fscrypt_dummy_policy dummy_enc_policy;
};
/* mount state */
......@@ -154,9 +157,11 @@ struct ceph_fs_client {
#ifdef CONFIG_CEPH_FSCACHE
struct fscache_volume *fscache;
#endif
#ifdef CONFIG_FS_ENCRYPTION
struct fscrypt_dummy_policy fsc_dummy_enc_policy;
#endif
};
/*
* File i/o capability. This tracks shared state with the metadata
* server that allows us to cache or writeback attributes or to read
......@@ -419,6 +424,11 @@ struct ceph_inode_info {
u32 i_truncate_seq; /* last truncate to smaller size */
u64 i_truncate_size; /* and the size we last truncated down to */
int i_truncate_pending; /* still need to call vmtruncate */
/*
* For none fscrypt case it equals to i_truncate_size or it will
* equals to fscrypt_file_size
*/
u64 i_truncate_pagecache_size;
u64 i_max_size; /* max file size authorized by mds */
u64 i_reported_size; /* (max_)size reported to or requested of mds */
......@@ -449,6 +459,13 @@ struct ceph_inode_info {
struct work_struct i_work;
unsigned long i_work_mask;
#ifdef CONFIG_FS_ENCRYPTION
u32 fscrypt_auth_len;
u32 fscrypt_file_len;
u8 *fscrypt_auth;
u8 *fscrypt_file;
#endif
};
struct ceph_netfs_request_data {
......@@ -998,6 +1015,7 @@ static inline bool __ceph_have_pending_cap_snap(struct ceph_inode_info *ci)
/* inode.c */
struct ceph_mds_reply_info_in;
struct ceph_mds_reply_dirfrag;
struct ceph_acl_sec_ctx;
extern const struct inode_operations ceph_file_iops;
......@@ -1005,8 +1023,14 @@ extern struct inode *ceph_alloc_inode(struct super_block *sb);
extern void ceph_evict_inode(struct inode *inode);
extern void ceph_free_inode(struct inode *inode);
struct inode *ceph_new_inode(struct inode *dir, struct dentry *dentry,
umode_t *mode, struct ceph_acl_sec_ctx *as_ctx);
void ceph_as_ctx_to_req(struct ceph_mds_request *req,
struct ceph_acl_sec_ctx *as_ctx);
extern struct inode *ceph_get_inode(struct super_block *sb,
struct ceph_vino vino);
struct ceph_vino vino,
struct inode *newino);
extern struct inode *ceph_get_snapdir(struct inode *parent);
extern int ceph_fill_file_size(struct inode *inode, int issued,
u32 truncate_seq, u64 truncate_size, u64 size);
......@@ -1065,7 +1089,13 @@ static inline int ceph_do_getattr(struct inode *inode, int mask, bool force)
}
extern int ceph_permission(struct mnt_idmap *idmap,
struct inode *inode, int mask);
extern int __ceph_setattr(struct inode *inode, struct iattr *attr);
struct ceph_iattr {
struct ceph_fscrypt_auth *fscrypt_auth;
};
extern int __ceph_setattr(struct inode *inode, struct iattr *attr,
struct ceph_iattr *cia);
extern int ceph_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *attr);
extern int ceph_getattr(struct mnt_idmap *idmap,
......@@ -1099,6 +1129,9 @@ struct ceph_acl_sec_ctx {
#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
void *sec_ctx;
u32 sec_ctxlen;
#endif
#ifdef CONFIG_FS_ENCRYPTION
struct ceph_fscrypt_auth *fscrypt_auth;
#endif
struct ceph_pagelist *pagelist;
};
......@@ -1237,6 +1270,8 @@ extern int ceph_encode_dentry_release(void **p, struct dentry *dn,
struct inode *dir,
int mds, int drop, int unless);
extern int __ceph_get_caps(struct inode *inode, struct ceph_file_info *fi,
int need, int want, loff_t endoff, int *got);
extern int ceph_get_caps(struct file *filp, int need, int want,
loff_t endoff, int *got);
extern int ceph_try_get_caps(struct inode *inode,
......@@ -1272,6 +1307,9 @@ extern int ceph_renew_caps(struct inode *inode, int fmode);
extern int ceph_open(struct inode *inode, struct file *file);
extern int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
struct file *file, unsigned flags, umode_t mode);
extern ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
struct iov_iter *to, int *retry_op,
u64 *last_objver);
extern int ceph_release(struct inode *inode, struct file *filp);
extern void ceph_fill_inline_data(struct inode *inode, struct page *locked_page,
char *data, size_t len);
......@@ -1375,4 +1413,9 @@ extern bool ceph_quota_update_statfs(struct ceph_fs_client *fsc,
struct kstatfs *buf);
extern void ceph_cleanup_quotarealms_inodes(struct ceph_mds_client *mdsc);
bool ceph_inc_mds_stopping_blocker(struct ceph_mds_client *mdsc,
struct ceph_mds_session *session);
void ceph_dec_mds_stopping_blocker(struct ceph_mds_client *mdsc);
bool ceph_inc_osd_stopping_blocker(struct ceph_mds_client *mdsc);
void ceph_dec_osd_stopping_blocker(struct ceph_mds_client *mdsc);
#endif /* _FS_CEPH_SUPER_H */
......@@ -352,6 +352,24 @@ static ssize_t ceph_vxattrcb_auth_mds(struct ceph_inode_info *ci,
return ret;
}
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
static bool ceph_vxattrcb_fscrypt_auth_exists(struct ceph_inode_info *ci)
{
return ci->fscrypt_auth_len;
}
static ssize_t ceph_vxattrcb_fscrypt_auth(struct ceph_inode_info *ci,
char *val, size_t size)
{
if (size) {
if (size < ci->fscrypt_auth_len)
return -ERANGE;
memcpy(val, ci->fscrypt_auth, ci->fscrypt_auth_len);
}
return ci->fscrypt_auth_len;
}
#endif /* CONFIG_FS_ENCRYPTION */
#define CEPH_XATTR_NAME(_type, _name) XATTR_CEPH_PREFIX #_type "." #_name
#define CEPH_XATTR_NAME2(_type, _name, _name2) \
XATTR_CEPH_PREFIX #_type "." #_name "." #_name2
......@@ -500,6 +518,15 @@ static struct ceph_vxattr ceph_common_vxattrs[] = {
.exists_cb = NULL,
.flags = VXATTR_FLAG_READONLY,
},
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
{
.name = "ceph.fscrypt.auth",
.name_size = sizeof("ceph.fscrypt.auth"),
.getxattr_cb = ceph_vxattrcb_fscrypt_auth,
.exists_cb = ceph_vxattrcb_fscrypt_auth_exists,
.flags = VXATTR_FLAG_READONLY,
},
#endif /* CONFIG_FS_ENCRYPTION */
{ .name = NULL, 0 } /* Required table terminator */
};
......@@ -1407,6 +1434,9 @@ void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx)
#endif
#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
security_release_secctx(as_ctx->sec_ctx, as_ctx->sec_ctxlen);
#endif
#ifdef CONFIG_FS_ENCRYPTION
kfree(as_ctx->fscrypt_auth);
#endif
if (as_ctx->pagelist)
ceph_pagelist_release(as_ctx->pagelist);
......
......@@ -359,14 +359,19 @@ enum {
extern const char *ceph_mds_op_name(int op);
#define CEPH_SETATTR_MODE 1
#define CEPH_SETATTR_UID 2
#define CEPH_SETATTR_GID 4
#define CEPH_SETATTR_MTIME 8
#define CEPH_SETATTR_ATIME 16
#define CEPH_SETATTR_SIZE 32
#define CEPH_SETATTR_CTIME 64
#define CEPH_SETATTR_MODE (1 << 0)
#define CEPH_SETATTR_UID (1 << 1)
#define CEPH_SETATTR_GID (1 << 2)
#define CEPH_SETATTR_MTIME (1 << 3)
#define CEPH_SETATTR_ATIME (1 << 4)
#define CEPH_SETATTR_SIZE (1 << 5)
#define CEPH_SETATTR_CTIME (1 << 6)
#define CEPH_SETATTR_MTIME_NOW (1 << 7)
#define CEPH_SETATTR_ATIME_NOW (1 << 8)
#define CEPH_SETATTR_BTIME (1 << 9)
#define CEPH_SETATTR_KILL_SGUID (1 << 10)
#define CEPH_SETATTR_FSCRYPT_AUTH (1 << 11)
#define CEPH_SETATTR_FSCRYPT_FILE (1 << 12)
/*
* Ceph setxattr request flags.
......@@ -462,24 +467,26 @@ union ceph_mds_request_args {
} __attribute__ ((packed));
union ceph_mds_request_args_ext {
union ceph_mds_request_args old;
struct {
__le32 mode;
__le32 uid;
__le32 gid;
struct ceph_timespec mtime;
struct ceph_timespec atime;
__le64 size, old_size; /* old_size needed by truncate */
__le32 mask; /* CEPH_SETATTR_* */
struct ceph_timespec btime;
} __attribute__ ((packed)) setattr_ext;
union {
union ceph_mds_request_args old;
struct {
__le32 mode;
__le32 uid;
__le32 gid;
struct ceph_timespec mtime;
struct ceph_timespec atime;
__le64 size, old_size; /* old_size needed by truncate */
__le32 mask; /* CEPH_SETATTR_* */
struct ceph_timespec btime;
} __attribute__ ((packed)) setattr_ext;
};
};
#define CEPH_MDS_FLAG_REPLAY 1 /* this is a replayed op */
#define CEPH_MDS_FLAG_WANT_DENTRY 2 /* want dentry in reply */
#define CEPH_MDS_FLAG_ASYNC 4 /* request is asynchronous */
struct ceph_mds_request_head_old {
struct ceph_mds_request_head_legacy {
__le64 oldest_client_tid;
__le32 mdsmap_epoch; /* on client */
__le32 flags; /* CEPH_MDS_FLAG_* */
......@@ -492,9 +499,9 @@ struct ceph_mds_request_head_old {
union ceph_mds_request_args args;
} __attribute__ ((packed));
#define CEPH_MDS_REQUEST_HEAD_VERSION 1
#define CEPH_MDS_REQUEST_HEAD_VERSION 2
struct ceph_mds_request_head {
struct ceph_mds_request_head_old {
__le16 version; /* struct version */
__le64 oldest_client_tid;
__le32 mdsmap_epoch; /* on client */
......@@ -508,6 +515,23 @@ struct ceph_mds_request_head {
union ceph_mds_request_args_ext args;
} __attribute__ ((packed));
struct ceph_mds_request_head {
__le16 version; /* struct version */
__le64 oldest_client_tid;
__le32 mdsmap_epoch; /* on client */
__le32 flags; /* CEPH_MDS_FLAG_* */
__u8 num_retry, num_fwd; /* legacy count retry and fwd attempts */
__le16 num_releases; /* # include cap/lease release records */
__le32 op; /* mds op code */
__le32 caller_uid, caller_gid;
__le64 ino; /* use this ino for openc, mkdir, mknod,
etc. (if replaying) */
union ceph_mds_request_args_ext args;
__le32 ext_num_retry; /* new count retry attempts */
__le32 ext_num_fwd; /* new count fwd attempts */
} __attribute__ ((packed));
/* cap/lease release record */
struct ceph_mds_request_release {
__le64 ino, cap_id; /* ino and unique cap id */
......
This diff is collapsed.
This diff is collapsed.
......@@ -523,6 +523,10 @@ struct ceph_osd_op {
struct {
__le64 cookie;
} __attribute__ ((packed)) notify;
struct {
__le64 unused;
__le64 ver;
} __attribute__ ((packed)) assert_ver;
struct {
__le64 offset, length;
__le64 src_offset;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment