From 208d2fdb2d7b266b1eb9c593d3b3217d55fe96c6 Mon Sep 17 00:00:00 2001 From: sageweil Date: Mon, 17 Dec 2007 21:47:34 +0000 Subject: [PATCH] slfixed slab corruption in mds reply parsing; opendir now opens directories as needed git-svn-id: https://ceph.svn.sf.net/svnroot/ceph@2215 29311d96-e01e-0410-9327-a35deaab8ce9 --- trunk/ceph/kernel/dir.c | 114 +++++++++++++++++++++++---------- trunk/ceph/kernel/inode.c | 6 +- trunk/ceph/kernel/mds_client.c | 15 +++-- trunk/ceph/kernel/super.c | 22 ++++--- trunk/ceph/kernel/super.h | 2 +- 5 files changed, 109 insertions(+), 50 deletions(-) diff --git a/trunk/ceph/kernel/dir.c b/trunk/ceph/kernel/dir.c index bf86ea2534200..604309627f135 100644 --- a/trunk/ceph/kernel/dir.c +++ b/trunk/ceph/kernel/dir.c @@ -6,6 +6,67 @@ int ceph_dir_debug = 50; const struct inode_operations ceph_dir_iops; const struct file_operations ceph_dir_fops; +/* + * ugly hack. + * - no locking. + * - should stop at mount root or current's CWD? + */ +static int get_dentry_path(struct dentry *dn, char *buf, struct dentry *base) +{ + int len; + dout(20, "get_dentry_path in dn %p bas %p\n", dn, base); + if (dn == base) + return 0; + + len = get_dentry_path(dn->d_parent, buf, base); + dout(20, "get_dentry_path out dn %p bas %p len %d adding %s\n", + dn, base, len, dn->d_name.name); + + buf[len++] = '/'; + memcpy(buf+len, dn->d_name.name, dn->d_name.len); + len += dn->d_name.len; + buf[len] = 0; + return len; +} + +struct ceph_inode_cap *ceph_open(struct inode *inode, struct file *file, int flags) +{ + struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc; + char path[PATH_MAX]; + int pathlen; + struct ceph_msg *req; + struct ceph_mds_request_head *rhead; + struct ceph_mds_reply_info rinfo; + struct dentry *dentry; + int frommds; + struct ceph_inode_cap *cap; + int err; + + dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); + + dout(5, "open inode %p dentry %p name '%s' flags %d\n", inode, dentry, dentry->d_name.name, flags); + pathlen = get_dentry_path(dentry, path, inode->i_sb->s_root); + dout(5, "path is %s len %d\n", path, pathlen); + + /* stat mds */ + req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_OPEN, + inode->i_sb->s_root->d_inode->i_ino, path, 0, 0); + if (IS_ERR(req)) + return ERR_PTR(PTR_ERR(req)); + rhead = req->front.iov_base; + rhead->args.open.flags = cpu_to_le32(flags); + if ((err = ceph_mdsc_do_request(mdsc, req, &rinfo, -1)) < 0) + return ERR_PTR(err); + + dout(10, "open got and parsed result\n"); + frommds = rinfo.reply->hdr.src.name.num; + cap = ceph_add_cap(inode, frommds, + le32_to_cpu(rinfo.head->file_caps), + le32_to_cpu(rinfo.head->file_caps_seq)); + return cap; +} + static int ceph_dir_open(struct inode *inode, struct file *file) { struct ceph_inode_info *ci = ceph_inode(inode); @@ -16,7 +77,9 @@ static int ceph_dir_open(struct inode *inode, struct file *file) cap = ceph_find_cap(inode, 0); if (!cap) { /* open this inode */ - BUG_ON(1); // writeme + cap = ceph_open(inode, file, O_DIRECTORY); + if (IS_ERR(cap)) + return PTR_ERR(cap); } fi = kzalloc(sizeof(*fi), GFP_KERNEL); @@ -51,7 +114,7 @@ static int ceph_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) int err; int i; struct qstr dname; - struct dentry *dn; + struct dentry *parent, *dn; struct inode *in; nextfrag: @@ -64,7 +127,7 @@ nextfrag: if (fi->rinfo.reply) ceph_mdsc_destroy_reply_info(&fi->rinfo); - dout(10, "dir_readdir querying mds for frag %u\n", frag); + dout(10, "dir_readdir querying mds for ino %lu frag %u\n", filp->f_dentry->d_inode->i_ino, frag); req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_READDIR, filp->f_dentry->d_inode->i_ino, "", 0, 0); if (IS_ERR(req)) @@ -76,19 +139,24 @@ nextfrag: dout(10, "dir_readdir got and parsed readdir result on frag %u\n", frag); /* pre-populate dentry cache */ - if (0) for (i=0; irinfo.dir_nr; i++) { + parent = filp->f_dentry; + for (i=0; irinfo.dir_nr; i++) { dname.name = fi->rinfo.dir_dname[i]; dname.len = fi->rinfo.dir_dname_len[i]; dname.hash = full_name_hash(dname.name, dname.len); - dn = d_alloc(filp->f_dentry, &dname); - if (dn == NULL) - break; + dn = d_alloc(parent, &dname); + if (dn == NULL) { + dout(30, "d_alloc badness\n"); + break; + } in = new_inode(parent->d_sb); if (in == NULL) { + dout(30, "new_inode badness\n"); d_delete(dn); break; } if (ceph_fill_inode(in, fi->rinfo.dir_in[i].in) < 0) { + dout(30, "ceph_fill_inode badness\n"); iput(in); d_delete(dn); break; @@ -100,7 +168,7 @@ nextfrag: } while (off < fi->rinfo.dir_nr) { - dout(10, "dir_readdir off %d / %d\n", off, fi->rinfo.dir_nr); + dout(10, "dir_readdir off %d / %d name '%s'\n", off, fi->rinfo.dir_nr, fi->rinfo.dir_dname[off]); if (filldir(dirent, fi->rinfo.dir_dname[off], fi->rinfo.dir_dname_len[off], @@ -113,9 +181,9 @@ nextfrag: off++; filp->f_pos++; } - // next frag? + + // next frag? FIXME *** - // done. dout(20, "dir_readdir done.\n"); return 0; } @@ -143,28 +211,6 @@ const struct file_operations ceph_dir_fops = { }; -/* - * ugly hack. - * - no locking. - * - should stop at mount root or current's CWD? - */ -static int get_dentry_path(struct dentry *dn, char *buf, struct dentry *base) -{ - int len; - dout(20, "get_dentry_path in dn %p bas %p\n", dn, base); - if (dn == base) - return 0; - - len = get_dentry_path(dn->d_parent, buf, base); - dout(20, "get_dentry_path out dn %p bas %p len %d adding %s\n", - dn, base, len, dn->d_name.name); - - buf[len++] = '/'; - memcpy(buf+len, dn->d_name.name, dn->d_name.len); - len += dn->d_name.len; - buf[len] = 0; - return len; -} static struct dentry *ceph_dir_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nameidata) @@ -187,7 +233,7 @@ static struct dentry *ceph_dir_lookup(struct inode *dir, struct dentry *dentry, req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_STAT, dir->i_sb->s_root->d_inode->i_ino, path, 0, 0); if (IS_ERR(req)) - return req; + return ERR_PTR(PTR_ERR(req)); if ((err = ceph_mdsc_do_request(mdsc, req, &rinfo, -1)) < 0) return ERR_PTR(err); @@ -197,7 +243,7 @@ static struct dentry *ceph_dir_lookup(struct inode *dir, struct dentry *dentry, if (!inode) return ERR_PTR(-EACCES); if ((err = ceph_fill_inode(inode, rinfo.trace_in[rinfo.trace_nr-1].in)) < 0) - return err; + return ERR_PTR(err); d_add(dentry, inode); return NULL; } diff --git a/trunk/ceph/kernel/inode.c b/trunk/ceph/kernel/inode.c index 5345ca5545492..2451d047e8b50 100644 --- a/trunk/ceph/kernel/inode.c +++ b/trunk/ceph/kernel/inode.c @@ -103,7 +103,7 @@ struct ceph_inode_cap *ceph_find_cap(struct inode *inode, int want) } -int ceph_add_cap(struct inode *inode, int mds, u32 cap, u32 seq) +struct ceph_inode_cap *ceph_add_cap(struct inode *inode, int mds, u32 cap, u32 seq) { struct ceph_inode_info *ci = ceph_inode(inode); int i; @@ -118,7 +118,7 @@ int ceph_add_cap(struct inode *inode, int mds, u32 cap, u32 seq) if (ci->i_caps == NULL) { ci->i_caps = o; derr(0, "add_cap enomem\n"); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } memcpy(ci->i_caps, o, ci->i_nr_caps*sizeof(*ci->i_caps)); if (o != ci->i_caps_static) @@ -137,7 +137,7 @@ int ceph_add_cap(struct inode *inode, int mds, u32 cap, u32 seq) inode, inode->i_ino, i, cap, cap|ci->i_caps[i].caps, seq, mds); ci->i_caps[i].caps |= cap; ci->i_caps[i].seq = seq; - return 0; + return &ci->i_caps[i]; } diff --git a/trunk/ceph/kernel/mds_client.c b/trunk/ceph/kernel/mds_client.c index a41c8dca8d2e0..d8132f84eab2f 100644 --- a/trunk/ceph/kernel/mds_client.c +++ b/trunk/ceph/kernel/mds_client.c @@ -432,7 +432,11 @@ int parse_reply_info_trace(void **p, void *end, struct ceph_mds_reply_info *info /* alloc one longer shared array */ info->trace_nr = numi; - info->trace_in = kmalloc(numi * (2*sizeof(void*)+sizeof(*info->trace_in)), GFP_KERNEL); + info->trace_in = kmalloc(numi * (sizeof(*info->trace_in) + + sizeof(*info->trace_dir) + + sizeof(*info->trace_dname) + + sizeof(*info->trace_dname_len)), + GFP_KERNEL); if (info->trace_in == NULL) return -ENOMEM; info->trace_dir = (void*)(info->trace_in + numi); @@ -489,11 +493,14 @@ int parse_reply_info_dir(void **p, void *end, struct ceph_mds_reply_info *info) /* alloc large array */ info->dir_nr = num; - info->dir_in = kmalloc(3 * num * sizeof(void*), GFP_KERNEL); + info->dir_in = kmalloc(num * (sizeof(*info->dir_in) + + sizeof(*info->dir_dname) + + sizeof(*info->dir_dname_len)), + GFP_KERNEL); if (info->dir_in == NULL) return -ENOMEM; - info->dir_dname = (void*)(info->trace_in + num); - info->dir_dname_len = (void*)(info->trace_in + num*2); + info->dir_dname = (void*)(info->dir_in + num); + info->dir_dname_len = (void*)(info->dir_dname + num); while (num) { /* dentry, inode */ diff --git a/trunk/ceph/kernel/super.c b/trunk/ceph/kernel/super.c index c72632402b25e..db5c463eb02ec 100644 --- a/trunk/ceph/kernel/super.c +++ b/trunk/ceph/kernel/super.c @@ -347,12 +347,13 @@ static int parse_mount_args(int flags, char *options, const char *dev_name, stru return 0; } -int parse_open_reply(struct ceph_mds_client *mdsc, struct ceph_msg *reply, struct inode *inode) +int parse_open_reply(struct ceph_msg *reply, struct inode *inode) { struct ceph_mds_reply_head *head; struct ceph_mds_reply_info rinfo; int frommds = reply->hdr.src.name.num; int err; + struct ceph_inode_cap *cap; /* parse reply */ head = reply->front.iov_base; @@ -367,10 +368,11 @@ int parse_open_reply(struct ceph_mds_client *mdsc, struct ceph_msg *reply, struc return err; /* fill in cap */ - if ((err = ceph_add_cap(inode, frommds, - le32_to_cpu(head->file_caps), - le32_to_cpu(head->file_caps_seq))) < 0) - return err; + cap = ceph_add_cap(inode, frommds, + le32_to_cpu(head->file_caps), + le32_to_cpu(head->file_caps_seq)); + if (IS_ERR(cap)) + return PTR_ERR(cap); ceph_mdsc_destroy_reply_info(&rinfo); return 0; @@ -387,6 +389,7 @@ static int open_root_inode(struct super_block *sb, struct ceph_mount_args *args) struct ceph_mds_reply_info rinfo; int frommds; int err; + struct ceph_inode_cap *cap; /* open dir */ dout(30, "open_root_inode opening '%s'\n", args->path); @@ -406,10 +409,13 @@ static int open_root_inode(struct super_block *sb, struct ceph_mount_args *args) /* fill in cap */ frommds = rinfo.reply->hdr.src.name.num; - if ((err = ceph_add_cap(inode, frommds, - le32_to_cpu(rinfo.head->file_caps), - le32_to_cpu(rinfo.head->file_caps_seq))) < 0) + cap = ceph_add_cap(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; + } root = d_alloc_root(inode); if (root == NULL) { diff --git a/trunk/ceph/kernel/super.h b/trunk/ceph/kernel/super.h index 6fe39c841d127..41d386f205400 100644 --- a/trunk/ceph/kernel/super.h +++ b/trunk/ceph/kernel/super.h @@ -100,7 +100,7 @@ struct ceph_file_info { /* inode.c */ 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 int ceph_add_cap(struct inode *inode, int mds, u32 cap, u32 seq); +extern struct ceph_inode_cap *ceph_add_cap(struct inode *inode, int mds, u32 cap, u32 seq); extern int ceph_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); -- 2.39.5