From 347cccbe1031679e277d05cdc0d3c8bd4f8e4f00 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 11 Aug 2008 14:27:10 -0700 Subject: [PATCH] kclient: basic .snap dir support --- src/kernel/dir.c | 45 +++++++++++++++++++++++++++++++++++++-------- src/kernel/inode.c | 29 +++++++++++++++++++++++++---- src/kernel/super.c | 1 + src/kernel/super.h | 2 ++ 4 files changed, 65 insertions(+), 12 deletions(-) diff --git a/src/kernel/dir.c b/src/kernel/dir.c index 0e66b65b28be9..82a0f649bac77 100644 --- a/src/kernel/dir.c +++ b/src/kernel/dir.c @@ -43,11 +43,16 @@ char *ceph_build_dentry_path(struct dentry *dentry, int *plen, __u64 *base, retry: len = 0; for (temp = dentry; !IS_ROOT(temp);) { + struct inode *inode = temp->d_inode; if (len >= min && - temp->d_inode && + inode && + ceph_vino(inode).snap == CEPH_NOSNAP && !ceph_dentry_revalidate(temp, 0)) break; - len += 1 + temp->d_name.len; + if (inode && ceph_vino(inode).snap == CEPH_SNAPDIR) + len++; /* slash only */ + else + len += 1 + temp->d_name.len; temp = temp->d_parent; if (temp == NULL) { derr(1, "corrupt dentry %p\n", dentry); @@ -63,17 +68,21 @@ retry: pos = len; path[pos] = 0; /* trailing null */ for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) { - pos -= temp->d_name.len; - if (pos < 0) { - break; + if (temp->d_inode && + ceph_vino(temp->d_inode).snap == CEPH_SNAPDIR) { + dout(50, "build_path_dentry path+%d: %p SNAPDIR\n", + pos, temp); } else { + pos -= temp->d_name.len; + if (pos < 0) + break; strncpy(path + pos, temp->d_name.name, temp->d_name.len); dout(50, "build_path_dentry path+%d: %p '%.*s'\n", pos, temp, temp->d_name.len, path + pos); - if (pos) - path[--pos] = '/'; } + if (pos) + path[--pos] = '/'; temp = temp->d_parent; if (temp == NULL) { derr(1, "corrupt dentry\n"); @@ -136,6 +145,8 @@ nextfrag: char *path; int pathlen; u64 pathbase; + int op = ceph_vino(inode).snap == CEPH_SNAPDIR ? + CEPH_MDS_OP_LSSNAP:CEPH_MDS_OP_READDIR; frag = ceph_choose_frag(ceph_inode(inode), frag, 0); @@ -144,7 +155,7 @@ nextfrag: ceph_vinop(inode), frag); path = ceph_build_dentry_path(filp->f_dentry, &pathlen, &pathbase, 1); - req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_READDIR, + req = ceph_mdsc_create_request(mdsc, op, pathbase, path, 0, 0, filp->f_dentry, USE_AUTH_MDS); kfree(path); @@ -259,6 +270,17 @@ loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin) struct dentry *ceph_finish_lookup(struct ceph_mds_request *req, struct dentry *dentry, int err) { + struct ceph_client *client = ceph_client(dentry->d_sb); + + /* snap dir? */ + if (err == -ENOENT && + strcmp(dentry->d_name.name, client->mount_args.snapdir_name) == 0) { + struct inode *parent = dentry->d_parent->d_inode; + struct inode *inode = ceph_get_snapdir(parent); + d_add(dentry, inode); + err = 0; + } + if (err == -ENOENT) { /* no trace? */ if (req->r_reply_info.trace_numd == 0) { @@ -662,6 +684,13 @@ static int ceph_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) { struct inode *dir = dentry->d_parent->d_inode; + /* always validate snapped metadata, for now */ + if (ceph_vino(dir).snap != CEPH_NOSNAP) { + dout(10, "d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry, + dentry->d_name.len, dentry->d_name.name, dentry->d_inode); + return 1; + } + dout(10, "d_revalidate %p '%.*s' inode %p\n", dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); diff --git a/src/kernel/inode.c b/src/kernel/inode.c index 454e25311f479..0ff23030c7ce8 100644 --- a/src/kernel/inode.c +++ b/src/kernel/inode.c @@ -45,6 +45,23 @@ struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino) return inode; } +struct inode *ceph_get_snapdir(struct inode *parent) +{ + struct ceph_vino vino = { + .ino = ceph_vino(parent).ino, + .snap = CEPH_SNAPDIR, + }; + struct inode *inode = ceph_get_inode(parent->i_sb, vino); + if (IS_ERR(inode)) + return ERR_PTR(PTR_ERR(inode)); + inode->i_mode = parent->i_mode; + inode->i_uid = parent->i_uid; + inode->i_gid = parent->i_gid; + inode->i_op = &ceph_dir_iops; + inode->i_fop = &ceph_dir_fops; + return inode; +} + const struct inode_operations ceph_file_iops = { .setattr = ceph_setattr, @@ -631,11 +648,9 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, d_drop(dn); realdn = d_materialise_unique(dn, in); if (IS_ERR(realdn)) { - derr(0, "error splicing %p (%d) with %p (%d) " + derr(0, "error splicing %p (%d) " "inode %p ino %llx.%llx\n", - dn, atomic_read(&dn->d_count), - realdn, atomic_read(&realdn->d_count), - realdn->d_inode, + dn, atomic_read(&dn->d_count), in, ceph_vinop(realdn->d_inode)); if (prehash) *prehash = false; /* don't rehash on error */ @@ -901,6 +916,12 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, dput(parent); parent = NULL; + + if (d == rinfo->trace_numi-rinfo->trace_snapdirpos-1) { + struct inode *snapdir = ceph_get_snapdir(dn->d_inode); + dn = d_find_alias(snapdir); + dout(10, " snapdir dentry is %p\n", dn); + } continue; diff --git a/src/kernel/super.c b/src/kernel/super.c index 62326dcb64ffd..baec0b7666aeb 100644 --- a/src/kernel/super.c +++ b/src/kernel/super.c @@ -434,6 +434,7 @@ static int parse_mount_args(int flags, char *options, const char *dev_name, args->flags = CEPH_MOUNT_DEFAULT; args->osd_timeout = 5; /* seconds */ args->mount_attempts = 2; /* 2 attempts */ + args->snapdir_name = ".snap"; /* ip1[,ip2...]:/server/path */ c = strchr(dev_name, ':'); diff --git a/src/kernel/super.h b/src/kernel/super.h index ac38e0b44769a..0e66a2fe5aade 100644 --- a/src/kernel/super.h +++ b/src/kernel/super.h @@ -107,6 +107,7 @@ struct ceph_mount_args { struct ceph_entity_addr mon_addr[5]; int wsize; int osd_timeout; + char *snapdir_name; }; enum { @@ -513,6 +514,7 @@ extern const struct inode_operations ceph_file_iops; extern const struct inode_operations ceph_special_iops; extern struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino); +extern struct inode *ceph_get_snapdir(struct inode *parent); extern int ceph_fill_inode(struct inode *inode, struct ceph_mds_reply_info_in *iinfo, struct ceph_mds_reply_dirfrag *dirinfo); -- 2.39.5