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);
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");
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);
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);
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) {
{
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);
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,
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 */
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;