return 0;
}
-static int open_root_inode(struct ceph_client *client, struct ceph_mount_args *args)
+static int open_root_inode(struct ceph_client *client, struct ceph_mount_args *args, struct dentry **pmnt_root)
{
struct ceph_mds_client *mdsc = &client->mdsc;
- struct inode *inode;
- struct dentry *root;
+ struct inode *root_inode, *mnt_inode = NULL;
+ struct dentry *fs_root;
struct ceph_msg *req = 0;
struct ceph_mds_request_head *reqhead;
struct ceph_mds_reply_info rinfo;
int err;
struct ceph_inode_cap *cap;
struct ceph_inode_info *ci;
-
+
/* open dir */
dout(30, "open_root_inode opening '%s'\n", args->path);
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_OPEN, 1, args->path, 0, 0);
err = -EINVAL;
}
- /* create root inode */
- inode = iget_locked(client->sb, rinfo.trace_in[rinfo.trace_nr-1].in->ino);
- if (inode == NULL)
- return -ENOMEM;
- if (inode->i_state & I_NEW)
- unlock_new_inode(inode);
+ fs_root = client->sb->s_root;
+ if (fs_root == NULL) {
+ /* get the fs root inode. Note that this is not necessarily the root of
+ the mount */
+ err = ceph_get_inode(client->sb, le64_to_cpu(rinfo.trace_in[0].in->ino), &root_inode);
+ if (err < 0) {
+ return err;
+ }
+
+ fs_root = d_alloc_root(root_inode);
+ if (fs_root == NULL) {
+ err = -ENOMEM;
+ /* fixme: also close? */
+ goto out;
+ }
+ client->sb->s_root = fs_root;
+ } else {
+ root_inode = client->sb->s_root->d_inode;
+
+ BUG_ON (root_inode == NULL);
+ }
- if ((err = ceph_fill_inode(inode, rinfo.trace_in[rinfo.trace_nr-1].in)) < 0)
+ if ((err = ceph_fill_trace(client->sb, &rinfo, &mnt_inode, pmnt_root)) < 0)
goto out;
+ BUG_ON(*pmnt_root == NULL);
+
/* fill in cap */
frommds = rinfo.reply->hdr.src.name.num;
- cap = ceph_add_cap(inode, frommds,
+ cap = ceph_add_cap(mnt_inode, frommds,
le32_to_cpu(rinfo.head->file_caps),
le32_to_cpu(rinfo.head->file_caps_seq));
if (IS_ERR(cap)) {
err = PTR_ERR(cap);
goto out;
}
- ci = ceph_inode(inode);
- ci->i_nr_by_mode[FILE_MODE_PIN]++;
- root = d_alloc_root(inode);
- if (root == NULL) {
- err = -ENOMEM;
- /* fixme: also close? */
+ if (*pmnt_root == NULL) {
goto out;
}
- client->sb->s_root = root;
+ ci = ceph_inode(mnt_inode);
+ ci->i_nr_by_mode[FILE_MODE_PIN]++;
+
dout(30, "open_root_inode success.\n");
return 0;
out:
dout(30, "open_root_inode failure %d\n", err);
- iput(inode);
+ iput(root_inode);
+ iput(mnt_inode);
return err;
}
/*
* mount: join the ceph cluster.
*/
-int ceph_mount(struct ceph_client *client, struct ceph_mount_args *args)
+int ceph_mount(struct ceph_client *client, struct ceph_mount_args *args, struct dentry **pdroot)
{
struct ceph_msg *mount_msg;
int err;
}
dout(30, "mount opening base mountpoint\n");
- if ((err = open_root_inode(client, args)) < 0)
+ if ((err = open_root_inode(client, args, pdroot)) < 0)
return err;
dout(10, "mount success\n");
} else {
in=dn->d_inode;
}
-
- if (in->i_ino != fi->rinfo.dir_in[i].in->ino) {
+
+ if (in->i_ino != le64_to_cpu(fi->rinfo.dir_in[i].in->ino)) {
if (ceph_fill_inode(in, fi->rinfo.dir_in[i].in) < 0) {
dout(30, "ceph_fill_inode badness\n");
iput(in);
struct inode *inode;
int err;
ino_t ino;
+ int found = 0;
dout(5, "dir_lookup inode %p dentry %p '%s'\n", dir, dentry, dentry->d_name.name);
path = ceph_build_dentry_path(dentry, &pathlen);
if (!inode) {
inode = new_inode(dir->i_sb);
+ } else {
+ found++;
}
if (!inode) {
return ERR_PTR(err);
}
d_add(dentry, inode);
+
+ if (found) {
+ iput(inode);
+ }
+
} else {
dout(10, "no trace in reply? wtf.\n");
}
return NULL;
}
-static int ceph_fill_trace(struct super_block *sb, struct ceph_mds_reply_info *prinfo, struct inode **lastinode)
+int ceph_fill_trace(struct super_block *sb, struct ceph_mds_reply_info *prinfo,
+ struct inode **lastinode, struct dentry **lastdentry)
{
int err = 0;
struct qstr dname;
*lastinode = NULL;
}
+ if (lastdentry) {
+ *lastdentry = NULL;
+ }
+
dn = sb->s_root;
dget(dn);
in = dn->d_inode;
}
dput(parent);
- dput(dn);
+
+ if (lastdentry) {
+ *lastdentry = dn;
+ } else {
+ dput(dn);
+ }
if (lastinode) {
*lastinode = in;
err = le32_to_cpu(rinfo.head->result);
if (err == 0) {
- err = ceph_fill_trace(dir->i_sb, &rinfo, &inode);
+ err = ceph_fill_trace(dir->i_sb, &rinfo, &inode, NULL);
if (err < 0) {
goto done;
err = le32_to_cpu(rinfo.head->result);
if (err == 0) {
- err = ceph_fill_trace(dir->i_sb, &rinfo, &inode);
+ err = ceph_fill_trace(dir->i_sb, &rinfo, &inode, NULL);
if (err < 0) {
goto done;
err = le32_to_cpu(rinfo.head->result);
if (err == 0) {
/* inode_dec_link_count(inode); */
- err = ceph_fill_trace(dir->i_sb, &rinfo, &inode);
+ err = ceph_fill_trace(dir->i_sb, &rinfo, &inode, NULL);
if (err < 0) {
goto done_mkdir;
const struct inode_operations ceph_symlink_iops;
+int ceph_get_inode(struct super_block *sb, unsigned long ino, struct inode **pinode)
+{
+ BUG_ON(pinode == NULL);
+
+ *pinode = NULL;
+
+ *pinode = iget_locked(sb, ino);
+
+ if (*pinode == NULL)
+ return -ENOMEM;
+ if ((*pinode)->i_state & I_NEW)
+ unlock_new_inode(*pinode);
+
+ return 0;
+}
+
int ceph_fill_inode(struct inode *inode, struct ceph_mds_reply_inode *info)
{
struct ceph_inode_info *ci = ceph_inode(inode);
static struct inode *ceph_alloc_inode(struct super_block *sb)
{
struct ceph_inode_info *ci;
+
ci = kmem_cache_alloc(ceph_inode_cachep, GFP_KERNEL);
if (!ci)
return NULL;
ci->i_caps = ci->i_caps_static;
atomic_set(&ci->i_cap_count, 0);
+ dout(30, "ceph_alloc_inode sb=%p inode=%lu\n", sb, (&ci->vfs_inode)->i_ino);
return &ci->vfs_inode;
}
static void ceph_destroy_inode(struct inode *inode)
{
struct ceph_inode_info *ci = ceph_inode(inode);
+
+ dout(30, "ceph_destroy_inode sb=%p inode=%lu\n", inode->i_sb, inode->i_ino);
if (ci->i_caps != ci->i_caps_static)
kfree(ci->i_caps);
struct ceph_client *client;
int err;
int (*compare_super)(struct super_block *, void *) = ceph_compare_super;
+ struct dentry *droot;
dout(25, "ceph_get_sb\n");
}
client = sb->s_fs_info;
- if ((err = ceph_mount(client, &mount_args)) < 0)
+ if ((err = ceph_mount(client, &mount_args, &droot)) < 0)
goto out_splat;
dout(30, "ceph_get_sb %p finishing\n", sb);
- return simple_set_mnt(mnt, sb);
+ mnt->mnt_sb = sb;
+ mnt->mnt_root = droot;
+
+ dout(22, "droot inode = %ld\n", droot->d_inode->i_ino);
+
+ return 0;
out_splat:
up_write(&sb->s_umount);
static void ceph_kill_sb(struct super_block *s)
{
struct ceph_client *client = s->s_fs_info;
+
dout(1, "kill_sb %p\n", s);
kill_anon_super(s);
ceph_destroy_client(client);
/* client.c */
extern struct ceph_client *ceph_create_client(struct ceph_mount_args *args, struct super_block *sb);
extern void ceph_destroy_client(struct ceph_client *cl);
-extern int ceph_mount(struct ceph_client *client, struct ceph_mount_args *args);
+extern int ceph_mount(struct ceph_client *client, struct ceph_mount_args *args,
+ struct dentry **pmnt_root);
/* inode.c */
+extern int ceph_get_inode(struct super_block *sb, unsigned long ino, struct inode **pinode);
extern int ceph_fill_inode(struct inode *inode, struct ceph_mds_reply_inode *info);
extern struct ceph_inode_cap *ceph_find_cap(struct inode *inode, int want);
extern struct ceph_inode_cap *ceph_add_cap(struct inode *inode, int mds, u32 cap, u32 seq);
extern const struct inode_operations ceph_dir_iops;
extern const struct file_operations ceph_dir_fops;
extern char *ceph_build_dentry_path(struct dentry *dentry, int *len);
+extern int ceph_fill_trace(struct super_block *sb, struct ceph_mds_reply_info *prinfo,
+ struct inode **lastinode, struct dentry **lastdentry);
#endif /* _FS_CEPH_CEPH_H */