From c53144cc418d3711d8c9a788bfec61eccf51a02f Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sat, 19 Jan 2008 08:18:14 -0800 Subject: [PATCH] kernel: setattr; moved fill_trace to inode.c --- src/TODO | 7 + src/include/ceph_fs.h | 4 +- src/kernel/dir.c | 114 ++--------------- src/kernel/file.c | 1 + src/kernel/inode.c | 277 +++++++++++++++++++++++++++++++++++++--- src/kernel/mds_client.c | 13 +- src/kernel/messenger.h | 10 +- src/kernel/super.h | 2 + src/mds/Server.cc | 6 +- 9 files changed, 299 insertions(+), 135 deletions(-) diff --git a/src/TODO b/src/TODO index a2550f4020384..cf4c3387cfabb 100644 --- a/src/TODO +++ b/src/TODO @@ -29,6 +29,13 @@ kernel client - ceph_queue_read .. check READING bit? - +- vfs + - getattr should do an lstat? + - setattr needs to be implemented.. + - d_revalidate.. + - create + - truncate + - fix up open. it really shouldn't blindly use existing caps! - mds client - handle file caps, ack back to mds, etc. - actually flush dirty data, too diff --git a/src/include/ceph_fs.h b/src/include/ceph_fs.h index b663e0d61c91a..00b8f214674b0 100644 --- a/src/include/ceph_fs.h +++ b/src/include/ceph_fs.h @@ -369,8 +369,8 @@ struct ceph_mds_request_head { __u32 mode; } chmod; struct { - uid_t uid; - gid_t gid; + __s32 uid; + __s32 gid; } chown; struct { __u32 mode; diff --git a/src/kernel/dir.c b/src/kernel/dir.c index 5ba17ca900bdb..3216d6bdae3e8 100644 --- a/src/kernel/dir.c +++ b/src/kernel/dir.c @@ -162,8 +162,14 @@ nextfrag: d_add(dn, in); dout(10, "dir_readdir added dentry %p inode %lu %d/%d\n", dn, in->i_ino, i, fi->rinfo.dir_nr); + } else { + if (ceph_fill_inode(in, fi->rinfo.dir_in[i].in) < 0) { + dout(30, "ceph_fill_inode badness\n"); + break; + } } + dput(dn); } } @@ -243,7 +249,7 @@ static struct dentry *ceph_dir_lookup(struct inode *dir, struct dentry *dentry, ino_t ino; int found = 0; - dout(5, "dir_lookup inode %p dentry %p '%s'\n", dir, dentry, dentry->d_name.name); + dout(5, "dir_lookup dirinode %p dentry %p '%s'\n", dir, dentry, dentry->d_name.name); path = ceph_build_dentry_path(dentry, &pathlen); if (IS_ERR(path)) return ERR_PTR(PTR_ERR(path)); @@ -294,111 +300,6 @@ static struct dentry *ceph_dir_lookup(struct inode *dir, struct dentry *dentry, return NULL; } -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; - struct dentry *dn, *parent = NULL; - struct inode *in; - int i = 0; - - BUG_ON(sb == NULL); - - if (lastinode) { - *lastinode = NULL; - } - - if (lastdentry) { - *lastdentry = NULL; - } - - dn = sb->s_root; - dget(dn); - in = dn->d_inode; - - for (i=0; itrace_nr; i++) { - if (in->i_ino == prinfo->trace_in[i].in->ino) { - break; - } - } - - if (i == prinfo->trace_nr) { - dout(10, "ceph_fill_trace did not locate mounted root!\n"); - return -ENOENT; - } - - if ((err = ceph_fill_inode(in, prinfo->trace_in[i].in)) < 0) { - return err; - } - - for (++i; itrace_nr; i++) { - dput(parent); - parent = dn; - - dname.name = prinfo->trace_dname[i]; - dname.len = prinfo->trace_dname_len[i]; - dname.hash = full_name_hash(dname.name, dname.len); - - dn = d_lookup(parent, &dname); - - dout(30, "calling d_lookup on parent=%p name=%s returned %p\n", parent, dname.name, dn); - - if (!dn) { - dn = d_alloc(parent, &dname); - if (dn == NULL) { - dout(30, "d_alloc badness\n"); - break; - } - } - - if (!prinfo->trace_in[i].in) { - err = -ENOENT; - d_delete(dn); - dn = NULL; - break; - } - - if ((!dn->d_inode) || - (dn->d_inode->i_ino != prinfo->trace_in[i].in->ino)) { - in = new_inode(parent->d_sb); - if (in == NULL) { - dout(30, "new_inode badness\n"); - d_delete(dn); - dn = NULL; - break; - } - if (ceph_fill_inode(in, prinfo->trace_in[i].in) < 0) { - dout(30, "ceph_fill_inode badness\n"); - iput(in); - d_delete(dn); - dn = NULL; - break; - } - d_add(dn, in); - dout(10, "ceph_fill_trace added dentry %p inode %lu %d/%d\n", - dn, in->i_ino, i, prinfo->trace_nr); - } else { - in = dn->d_inode; - } - - } - - dput(parent); - - if (lastdentry) { - *lastdentry = dn; - } else { - dput(dn); - } - - if (lastinode) { - *lastinode = in; - } - - return err; -} - static int ceph_dir_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct ceph_client *client = dir->i_sb->s_fs_info; @@ -633,6 +534,7 @@ ceph_dir_create(struct inode *dir, struct dentry *dentry, int mode, const struct inode_operations ceph_dir_iops = { .lookup = ceph_dir_lookup, // .getattr = ceph_inode_getattr, + .setattr = ceph_setattr, .mknod = ceph_dir_mknod, .symlink = ceph_dir_symlink, .mkdir = ceph_dir_mkdir, diff --git a/src/kernel/file.c b/src/kernel/file.c index 7839e8d20f54c..e30b9ecff8575 100644 --- a/src/kernel/file.c +++ b/src/kernel/file.c @@ -103,6 +103,7 @@ int ceph_release(struct inode *inode, struct file *file) } const struct inode_operations ceph_file_iops = { + .setattr = ceph_setattr, /* .getattr = ceph_vfs_getattr, .setattr = ceph_vfs_setattr, */ diff --git a/src/kernel/inode.c b/src/kernel/inode.c index 73795bec1de07..cc4f5487cf1c6 100644 --- a/src/kernel/inode.c +++ b/src/kernel/inode.c @@ -12,20 +12,7 @@ int ceph_inode_debug = 50; #define DOUT_PREFIX "inode: " #include "super.h" -/* - * symlinks - */ -static void * ceph_sym_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - struct ceph_inode_info *ci = ceph_inode(dentry->d_inode); - nd_set_link(nd, ci->i_symlink); - return NULL; -} - -const struct inode_operations ceph_symlink_iops = { - .readlink = generic_readlink, - .follow_link = ceph_sym_follow_link, -}; +const struct inode_operations ceph_symlink_iops; int ceph_get_inode(struct super_block *sb, unsigned long ino, struct inode **pinode) { @@ -41,7 +28,8 @@ int ceph_get_inode(struct super_block *sb, unsigned long ino, struct inode **pin } /* - * populate an inode based on info from mds + * populate an inode based on info from mds. + * may be called on new or existing inodes. */ int ceph_fill_inode(struct inode *inode, struct ceph_mds_reply_inode *info) { @@ -132,6 +120,114 @@ int ceph_fill_inode(struct inode *inode, struct ceph_mds_reply_inode *info) return 0; } +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; + struct dentry *dn, *parent = NULL; + struct inode *in; + int i = 0; + + BUG_ON(sb == NULL); + + if (lastinode) + *lastinode = NULL; + + if (lastdentry) + *lastdentry = NULL; + + dn = sb->s_root; + dget(dn); + in = dn->d_inode; + + for (i=0; itrace_nr; i++) + if (in->i_ino == prinfo->trace_in[i].in->ino) + break; + + if (i == prinfo->trace_nr) { + dout(10, "ceph_fill_trace did not locate mounted root!\n"); + return -ENOENT; + } + + if ((err = ceph_fill_inode(in, prinfo->trace_in[i].in)) < 0) + return err; + + for (++i; itrace_nr; i++) { + dput(parent); + parent = dn; + + dname.name = prinfo->trace_dname[i]; + dname.len = prinfo->trace_dname_len[i]; + dname.hash = full_name_hash(dname.name, dname.len); + + dn = d_lookup(parent, &dname); + + dout(30, "calling d_lookup on parent=%p name=%s returned %p\n", parent, dname.name, dn); + + if (!dn) { + dn = d_alloc(parent, &dname); + if (dn == NULL) { + dout(30, "d_alloc badness\n"); + break; + } + } + + if (!prinfo->trace_in[i].in) { + err = -ENOENT; + d_delete(dn); + dn = NULL; + break; + } + + if ((!dn->d_inode) || + (dn->d_inode->i_ino != prinfo->trace_in[i].in->ino)) { + in = new_inode(parent->d_sb); + if (in == NULL) { + dout(30, "new_inode badness\n"); + d_delete(dn); + dn = NULL; + break; + } + if (ceph_fill_inode(in, prinfo->trace_in[i].in) < 0) { + dout(30, "ceph_fill_inode badness\n"); + iput(in); + d_delete(dn); + dn = NULL; + break; + } + d_add(dn, in); + dout(10, "ceph_fill_trace added dentry %p inode %lu %d/%d\n", + dn, in->i_ino, i, prinfo->trace_nr); + } else { + in = dn->d_inode; + if (ceph_fill_inode(in, prinfo->trace_in[i].in) < 0) { + dout(30, "ceph_fill_inode badness\n"); + break; + } + + } + + } + + dput(parent); + + if (lastdentry) + *lastdentry = dn; + else + dput(dn); + + if (lastinode) + *lastinode = in; + + return err; +} + + +/* + * capabilities + */ + struct ceph_inode_cap *ceph_find_cap(struct inode *inode, int want) { struct ceph_inode_info *ci = ceph_inode(inode); @@ -327,3 +423,154 @@ int ceph_handle_cap_grant(struct inode *inode, struct ceph_mds_file_caps *grant, return 0; } + + +/* + * symlinks + */ +static void * ceph_sym_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct ceph_inode_info *ci = ceph_inode(dentry->d_inode); + nd_set_link(nd, ci->i_symlink); + return NULL; +} + +const struct inode_operations ceph_symlink_iops = { + .readlink = generic_readlink, + .follow_link = ceph_sym_follow_link, +}; + + +/* + * generics + */ +struct ceph_msg * prepare_setattr(struct ceph_mds_client *mdsc, struct dentry *dentry, int op) +{ + char *path; + int pathlen; + struct ceph_msg *req; + + dout(5, "prepare_setattr dentry %p\n", dentry); + path = ceph_build_dentry_path(dentry, &pathlen); + if (IS_ERR(path)) + return ERR_PTR(PTR_ERR(path)); + req = ceph_mdsc_create_request(mdsc, op, dentry->d_inode->i_sb->s_root->d_inode->i_ino, path, 0, 0); + kfree(path); + return req; +} + +int ceph_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + struct ceph_client *client = inode->i_sb->s_fs_info; + struct ceph_mds_client *mdsc = &client->mdsc; + const unsigned int ia_valid = attr->ia_valid; + struct ceph_msg *req; + struct ceph_mds_request_head *reqh; + struct ceph_mds_reply_info rinfo; + int err; + + /* gratuitous debug output */ + if (ia_valid & ATTR_UID) + dout(10, "uid %d -> %d\n", inode->i_uid, attr->ia_uid); + if (ia_valid & ATTR_GID) + dout(10, "gid %d -> %d\n", inode->i_uid, attr->ia_uid); + if (ia_valid & ATTR_MODE) + dout(10, "mode %d -> %d\n", inode->i_mode, attr->ia_mode); + if (ia_valid & ATTR_SIZE) + dout(10, "size %lld -> %lld\n", inode->i_size, attr->ia_size); + if (ia_valid & ATTR_ATIME) + dout(10, "atime %ld.%ld -> %ld.%ld\n", + inode->i_atime.tv_sec, inode->i_atime.tv_nsec, + attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec); + if (ia_valid & ATTR_MTIME) + dout(10, "mtime %ld.%ld -> %ld.%ld\n", + inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec, + attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec); + if (ia_valid & ATTR_FILE) + dout(10, "ATTR_FILE ... hrm!\n"); + + /* chown */ + if (ia_valid & (ATTR_UID|ATTR_GID)) { + req = prepare_setattr(mdsc, dentry, CEPH_MDS_OP_CHOWN); + if (IS_ERR(req)) + return PTR_ERR(req); + reqh = req->front.iov_base; + if (ia_valid & ATTR_UID) + reqh->args.chown.uid = cpu_to_le32(attr->ia_uid); + else + reqh->args.chown.uid = cpu_to_le32(-1); + if (ia_valid & ATTR_GID) + reqh->args.chown.gid = cpu_to_le32(attr->ia_gid); + else + reqh->args.chown.gid = cpu_to_le32(-1); + if ((err = ceph_mdsc_do_request(mdsc, req, &rinfo, 0)) < 0) + return err; + err = le32_to_cpu(rinfo.head->result); + dout(10, "chown result %d\n", err); + if (err) + return err; + err = ceph_fill_trace(inode->i_sb, &rinfo, &inode, NULL); + //if (err) return err; + } + + /* chmod? */ + if (ia_valid & ATTR_MODE) { + req = prepare_setattr(mdsc, dentry, CEPH_MDS_OP_CHMOD); + if (IS_ERR(req)) + return PTR_ERR(req); + reqh = req->front.iov_base; + reqh->args.chmod.mode = cpu_to_le32(attr->ia_mode); + if ((err = ceph_mdsc_do_request(mdsc, req, &rinfo, 0)) < 0) + return err; + err = le32_to_cpu(rinfo.head->result); + dout(10, "chmod result %d\n", err); + if (err) + return err; + err = ceph_fill_trace(inode->i_sb, &rinfo, &inode, NULL); + //if (err) return err; + } + + /* FIXME: does getattr get set to do regular mtime updates? */ + /* utimes */ + if (ia_valid & (ATTR_ATIME|ATTR_MTIME)) { + req = prepare_setattr(mdsc, dentry, CEPH_MDS_OP_UTIME); + if (IS_ERR(req)) + return PTR_ERR(req); + reqh = req->front.iov_base; + ceph_encode_timespec(&reqh->args.utime.mtime, &attr->ia_mtime); + ceph_encode_timespec(&reqh->args.utime.atime, &attr->ia_atime); + if ((err = ceph_mdsc_do_request(mdsc, req, &rinfo, 0)) < 0) + return err; + err = le32_to_cpu(rinfo.head->result); + dout(10, "utime result %d\n", err); + if (err) + return err; + err = ceph_fill_trace(inode->i_sb, &rinfo, &inode, NULL); + //if (err) return err; + } + + /* truncate? */ + if (ia_valid & ATTR_SIZE) { + if (ia_valid & ATTR_FILE) + req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_TRUNCATE, + dentry->d_inode->i_ino, "", 0, 0); + else + req = prepare_setattr(mdsc, dentry, CEPH_MDS_OP_TRUNCATE); + if (IS_ERR(req)) + return PTR_ERR(req); + reqh = req->front.iov_base; + reqh->args.truncate.length = cpu_to_le64(attr->ia_size); + if ((err = ceph_mdsc_do_request(mdsc, req, &rinfo, 0)) < 0) + return err; + err = le32_to_cpu(rinfo.head->result); + dout(10, "truncate result %d\n", err); + if (err) + return err; + err = ceph_fill_trace(inode->i_sb, &rinfo, &inode, NULL); + //if (err) return err; + } + + return 0; +} + diff --git a/src/kernel/mds_client.c b/src/kernel/mds_client.c index b85ff292b7c3a..75f083198ac07 100644 --- a/src/kernel/mds_client.c +++ b/src/kernel/mds_client.c @@ -783,6 +783,7 @@ void send_mds_reconnect(struct ceph_mds_client *mdsc, int mds) int pathlen, err; struct dentry *dentry; struct ceph_inode_info *ci; + struct ceph_mds_cap_reconnect *rec; dout(10, "send_mds_reconnect mds%d\n", mds); @@ -827,11 +828,13 @@ void send_mds_reconnect(struct ceph_mds_client *mdsc, int mds) dout(10, "cap is %p, ci is %p, inode is %p\n", cap, ci, &ci->vfs_inode); dout(10, " adding cap %p on ino %lx\n", cap, ci->vfs_inode.i_ino); ceph_encode_64(&p, end, ci->vfs_inode.i_ino); - ceph_encode_32(&p, end, ceph_caps_wanted(ci)); - ceph_encode_32(&p, end, ceph_caps_issued(ci)); - ceph_encode_64(&p, end, ci->i_wr_size); - ceph_encode_timespec(&p, end, &ci->vfs_inode.i_mtime); //i_wr_mtime - ceph_encode_timespec(&p, end, &ci->vfs_inode.i_atime); /* atime.. fixme */ + rec = p; + BUG_ON(p + sizeof(*rec) > end); + rec->wanted = cpu_to_le32(ceph_caps_wanted(ci)); + rec->issued = cpu_to_le32(ceph_caps_issued(ci)); + rec->size = cpu_to_le64(ci->i_wr_size); + ceph_encode_timespec(&rec->mtime, &ci->vfs_inode.i_mtime); //i_wr_mtime + ceph_encode_timespec(&rec->atime, &ci->vfs_inode.i_atime); /* atime.. fixme */ dentry = d_find_alias(&ci->vfs_inode); path = ceph_build_dentry_path(dentry, &pathlen); if (IS_ERR(path)) { diff --git a/src/kernel/messenger.h b/src/kernel/messenger.h index 3cbe178548fee..73452430c86a5 100644 --- a/src/kernel/messenger.h +++ b/src/kernel/messenger.h @@ -282,12 +282,12 @@ static __inline__ void ceph_decode_timespec(struct timespec *ts, struct ceph_tim ts->tv_sec = le32_to_cpu(tv->tv_sec); ts->tv_nsec = 1000*le32_to_cpu(tv->tv_usec); } - -static __inline__ int ceph_encode_timespec(void **p, void *end, struct timespec *ts) +static __inline__ int ceph_encode_timespec(struct ceph_timeval *tv, struct timespec *ts) { - BUG_ON(*p + sizeof(struct ceph_timeval) > end); - ceph_encode_32(p, end, ts->tv_sec); - ceph_encode_32(p, end, ts->tv_nsec/1000); + int usec = ts->tv_nsec; + do_div(usec, 1000); + tv->tv_sec = cpu_to_le32(ts->tv_sec); + tv->tv_usec = cpu_to_le32(usec); return 0; } diff --git a/src/kernel/super.h b/src/kernel/super.h index 528fe045f8af0..726ce8b520ff6 100644 --- a/src/kernel/super.h +++ b/src/kernel/super.h @@ -223,6 +223,8 @@ extern void ceph_remove_cap(struct ceph_inode_info *ci, int mds); extern void ceph_remove_caps(struct ceph_inode_info *ci); extern int ceph_handle_cap_grant(struct inode *inode, struct ceph_mds_file_caps *grant, struct ceph_mds_session *session); +extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); + /* addr.c */ extern const struct address_space_operations ceph_aops; diff --git a/src/mds/Server.cc b/src/mds/Server.cc index 9c58b79b17638..b3c73ff709dbf 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -1593,8 +1593,10 @@ void Server::handle_client_chown(MDRequest *mdr) // project update inode_t *pi = cur->project_inode(); - pi->uid = MAX(req->head.args.chown.uid, 0); - pi->gid = MAX(req->head.args.chown.gid, 0); + if (req->head.args.chown.uid != -1) + pi->uid = req->head.args.chown.uid; + if (req->head.args.chown.gid != -1) + pi->gid = req->head.args.chown.gid; pi->version = cur->pre_dirty(); pi->ctime = g_clock.real_now(); -- 2.39.5