Project

General

Profile

Feature #22105 ยป snap_export.patch

Zheng Yan, 11/14/2017 02:46 PM

View differences:

fs/ceph/export.c
u64 ino, parent_ino;
} __attribute__ ((packed));
/*
* fh for snapped inode
*/
struct ceph_nfs_snapfh {
u64 ino;
u64 snapid;
u64 parent_ino;
u32 hash;
} __attribute__ ((packed));
static int ceph_encode_snapfh(struct inode *inode, u32 *rawfh, int *max_len,
struct inode *parent_inode)
{
const static int snap_handle_length =
sizeof(struct ceph_nfs_snapfh) >> 2;
struct ceph_nfs_snapfh *sfh = (void *)rawfh;
u64 snapid = ceph_snap(inode);
bool no_parent = true;
if (*max_len < snap_handle_length) {
*max_len = snap_handle_length;
return FILEID_INVALID;
}
if (snapid != CEPH_SNAPDIR) {
struct inode *dir;
struct dentry *dentry = d_find_alias(inode);
if (!dentry)
return -EINVAL;
rcu_read_lock();
dir = d_inode_rcu(dentry->d_parent);
if (ceph_snap(dir) != CEPH_SNAPDIR) {
sfh->parent_ino = ceph_ino(dir);
sfh->hash = ceph_dentry_hash(dir, dentry);
no_parent = false;
}
rcu_read_unlock();
dput(dentry);
}
sfh->ino = ceph_ino(inode);
sfh->snapid = snapid;
if (no_parent) {
sfh->parent_ino = sfh->ino;
sfh->hash = 0;
}
*max_len = snap_handle_length;
return FILEID_BTRFS_WITH_PARENT;
}
static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
struct inode *parent_inode)
{
const static int handle_length =
sizeof(struct ceph_nfs_fh) >> 2;
const static int connected_handle_length =
sizeof(struct ceph_nfs_confh) >> 2;
int type;
struct ceph_nfs_fh *fh = (void *)rawfh;
struct ceph_nfs_confh *cfh = (void *)rawfh;
int connected_handle_length = sizeof(*cfh)/4;
int handle_length = sizeof(*fh)/4;
/* don't re-export snaps */
if (ceph_snap(inode) != CEPH_NOSNAP)
return -EINVAL;
return ceph_encode_snapfh(inode, rawfh, max_len, parent_inode);
if (parent_inode && (*max_len < connected_handle_length)) {
*max_len = connected_handle_length;
......
}
if (parent_inode) {
struct ceph_nfs_confh *cfh = (void *)rawfh;
dout("encode_fh %llx with parent %llx\n",
ceph_ino(inode), ceph_ino(parent_inode));
cfh->ino = ceph_ino(inode);
......
*max_len = connected_handle_length;
type = FILEID_INO32_GEN_PARENT;
} else {
struct ceph_nfs_fh *fh = (void *)rawfh;
dout("encode_fh %llx\n", ceph_ino(inode));
fh->ino = ceph_ino(inode);
*max_len = handle_length;
......
return d_obtain_alias(inode);
}
static struct dentry *__snapfh_to_dentry(struct super_block *sb,
struct ceph_nfs_snapfh *sfh,
bool want_parent)
{
struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
struct ceph_mds_request *req;
struct inode *inode;
struct ceph_vino vino;
int mask;
int err;
if (want_parent) {
vino.ino = sfh->parent_ino;
if (sfh->snapid == CEPH_SNAPDIR)
vino.snap = CEPH_NOSNAP;
else if (sfh->ino == sfh->parent_ino)
vino.snap = CEPH_SNAPDIR;
else
vino.snap = sfh->snapid;
} else {
vino.ino = sfh->ino;
vino.snap = sfh->snapid;
}
inode = ceph_find_inode(sb, vino);
if (inode)
return d_obtain_alias(inode);
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
USE_ANY_MDS);
if (IS_ERR(req))
return ERR_CAST(req);
mask = CEPH_STAT_CAP_INODE;
if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
mask |= CEPH_CAP_XATTR_SHARED;
req->r_args.lookupino.mask = cpu_to_le32(mask);
if (vino.snap < CEPH_NOSNAP) {
req->r_args.lookupino.snapid = cpu_to_le64(vino.snap);
if (!want_parent && sfh->ino != sfh->parent_ino) {
req->r_args.lookupino.parent = cpu_to_le64(sfh->parent_ino);
req->r_args.lookupino.hash = cpu_to_le32(sfh->hash);
}
}
req->r_ino1 = vino;
req->r_num_caps = 1;
err = ceph_mdsc_do_request(mdsc, NULL, req);
inode = req->r_target_inode;
if (inode) {
if (vino.snap == CEPH_SNAPDIR)
inode = ceph_get_snapdir(inode);
else if (ceph_snap(inode) == vino.snap)
ihold(inode);
else
inode = NULL;
}
ceph_mdsc_put_request(req);
if (!inode)
return ERR_PTR(-ESTALE);
if (inode->i_nlink == 0) {
iput(inode);
return ERR_PTR(-ESTALE);
}
return d_obtain_alias(inode);
}
/*
* convert regular fh to dentry
*/
......
{
struct ceph_nfs_fh *fh = (void *)fid->raw;
if (fh_type == FILEID_BTRFS_WITH_PARENT) {
struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
return __snapfh_to_dentry(sb, sfh, false);
}
if (fh_type != FILEID_INO32_GEN &&
fh_type != FILEID_INO32_GEN_PARENT)
return NULL;
......
static struct dentry *ceph_get_parent(struct dentry *child)
{
/* don't re-export snaps */
if (ceph_snap(d_inode(child)) != CEPH_NOSNAP)
return ERR_PTR(-EINVAL);
struct inode *inode = d_inode(child);
if (ceph_snap(inode) == CEPH_SNAPDIR)
return __fh_to_dentry(inode->i_sb, ceph_ino(inode));
if (ceph_snap(inode) < CEPH_NOSNAP) {
struct dentry *dn;
struct inode* dir;
if (!d_is_dir(child))
return ERR_PTR(-EINVAL);
dn = __fh_to_dentry(inode->i_sb, ceph_ino(inode));
if (IS_ERR_OR_NULL(dn))
return dn;
dir = ceph_get_snapdir(d_inode(dn));
dput(dn);
return d_obtain_alias(dir);
}
dout("get_parent %p ino %llx.%llx\n",
child, ceph_vinop(d_inode(child)));
dout("get_parent %p ino %llx.%llx\n", child, ceph_vinop(inode));
return __get_parent(child->d_sb, child, 0);
}
......
struct ceph_nfs_confh *cfh = (void *)fid->raw;
struct dentry *dentry;
if (fh_type == FILEID_BTRFS_WITH_PARENT) {
struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
return __snapfh_to_dentry(sb, sfh, true);
}
if (fh_type != FILEID_INO32_GEN_PARENT)
return NULL;
if (fh_len < sizeof(*cfh) / 4)
......
return dentry;
}
struct getdents_callback {
struct dir_context ctx;
struct file *file;
u64 ino;
u64 snap;
char *name;
unsigned sequence;
bool found;
};
static int filldir_one(struct dir_context *ctx, const char *name, int len,
loff_t pos, u64 ino, unsigned int d_type)
{
struct getdents_callback *buf =
container_of(ctx, struct getdents_callback, ctx);
struct ceph_file_info *fi = buf->file->private_data;
struct ceph_mds_reply_info_parsed *rinfo;
if (!fi->last_readdir)
return -1;
rinfo = &fi->last_readdir->r_reply_info;
if (!rinfo || !rinfo->dir_nr)
return true;
chunk_offset = rinfo->dir_entries[0].offset;
return new_pos < chunk_offset ||
is_hash_order(new_pos) != is_hash_order(chunk_offset);
int result = 0;
buf->sequence++;
}
static int __get_snap_name(struct dentry *parent, char *name,
struct dentry *child)
{
struct inode *inode = d_inode(child);
struct inode *dir = d_inode(child);
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
struct dir_context ctx = {
.actor = filldir_noop,
};
struct file *file;
if (ceph_ino(inode) != ceph_ino(dir))
return -EINVAL;
if (ceph_snap(inode) == CEPH_SNAPDIR) {
if (ceph_ino(dir) == CEPH_NOSNAP) {
return -EINVAL;
strcpy(name, fsc->mount_options->snapdir_name);
return 0;
}
if (ceph_snap(dir) != CEPH_SNAPDIR)
return -EINVAL;
file = dentry_open(path, O_RDONLY, cred);
if (IS_ERR(file))
goto out;
iterate_dir(file, &ctx)
}
static int ceph_get_name(struct dentry *parent, char *name,
struct dentry *child)
{
struct ceph_mds_client *mdsc;
struct ceph_mds_request *req;
struct inode *inode = d_inode(child);
int err;
mdsc = ceph_inode_to_client(d_inode(child))->mdsc;
if (ceph_snap(inode) != CEPH_NOSNAP)
return __get_snap_name(parent, name, child);
mdsc = ceph_inode_to_client(inode)->mdsc;
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
USE_ANY_MDS);
if (IS_ERR(req))
......
inode_lock(d_inode(parent));
req->r_inode = d_inode(child);
ihold(d_inode(child));
req->r_inode = inode;
ihold(inode);
req->r_ino2 = ceph_vino(d_inode(parent));
req->r_parent = d_inode(parent);
set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
......
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(d_inode(child)), name);
child, ceph_vinop(inode), name);
} else {
dout("get_name %p ino %llx.%llx err %d\n",
child, ceph_vinop(d_inode(child)), err);
child, ceph_vinop(inode), err);
}
ceph_mdsc_put_request(req);
include/linux/ceph/ceph_fs.h
__le64 length; /* num bytes to lock from start */
__u8 wait; /* will caller wait for lock to become available? */
} __attribute__ ((packed)) filelock_change;
struct {
__le32 mask; /* CEPH_CAP_* */
__le64 snapid;
__le64 parent;
__le32 hash;
} __attribute__ ((packed)) lookupino;
} __attribute__ ((packed));
#define CEPH_MDS_FLAG_REPLAY 1 /* this is a replayed op */
    (1-1/1)