#define MDS_REINT 2
#define MDS_READPAGE 3
-#define REINT_SETATTR 1
+#define REINT_SETATTR 0
+#define REINT_CREATE 1
+#define REINT_MAX 1
struct mds_req_hdr {
__u32 opc;
};
+/* MDS update records */
+
+struct mds_update_record_hdr {
+ __u32 ur_reclen;
+ __u32 ur_opcode;
+};
+
struct mds_rec_setattr {
- __u32 sa_len;
+ __u32 sa_reclen;
__u32 sa_opcode;
struct ll_fid sa_fid;
__u32 sa_valid;
__u32 sa_attr_flags;
};
+struct mds_rec_create {
+ __u32 cr_reclen;
+ __u32 cr_opcode;
+ struct ll_fid cr_fid;
+ __u32 cr_uid;
+ __u32 cr_gid;
+ __u64 cr_time;
+ __u32 cr_mode;
+ /* overloaded: id for create, tgtlen for symlink, rdev for mknod */
+ __u64 cr_id;
+ __u32 cr_namelen;
+ /* name here */
+};
+
#ifdef __KERNEL__
static inline void ll_ino2fid(struct ll_fid *fid, ino_t ino, __u32 generation, int type)
__u32 generation;
};
+struct mds_update_record {
+ __u32 ur_reclen;
+ __u32 ur_opcode;
+ struct ll_fid *ur_fid1;
+ struct ll_fid *ur_fid2;
+ int ur_namelen;
+ char *ur_name;
+ int ur_tgtlen;
+ char *ur_tgt;
+ struct iattr ur_iattr;
+ __u64 ur_id;
+ __u32 ur_mode;
+ __u32 ur_uid;
+ __u32 ur_gid;
+ __u64 ur_time;
+};
/* mds/mds_pack.c */
void *mds_req_tgt(struct mds_req *req);
int mds_unpack_rep(char *buf, int len, struct mds_rep_hdr **hdr, struct mds_rep **rep);
/* mds/mds_reint.c */
-int mds_reint_setattr(struct mds_request *req);
+int mds_reint_rec(struct mds_update_record *r, struct mds_request *req);
/* lib/mds_updates.c */
-void mds_setattr_unpack(struct mds_rec_setattr *rec, struct iattr *attr);
+int mds_update_unpack(char *buf, int len, struct mds_update_record *r);
+
void mds_setattr_pack(struct mds_rec_setattr *rec, struct inode *inode, struct iattr *iattr);
+void mds_create_pack(struct mds_rec_create *rec, struct inode *inode, char *name, __u32 mode, __u64 id, __u32 uid, __u32 gid, __u64 time);
/* mds/handler.c */
struct dentry *mds_fid2dentry(struct mds_obd *mds, struct ll_fid *fid, struct vfsmount **mnt);
struct mds_rep **mds_reply, struct mds_rep_hdr **hdr);
int mdc_readpage(ino_t ino, int type, __u64 offset, char *addr,
struct mds_rep **rep, struct mds_rep_hdr **hdr);
+int mdc_create(struct inode *dir, char *name, int mode, __u64 id,
+ __u32 uid, __u32 gid, __u64 time,
+ struct mds_rep **rep, struct mds_rep_hdr **hdr);
#define IOC_REQUEST_GETATTR _IOWR('f', 30, long)
#define IOC_REQUEST_READPAGE _IOWR('f', 31, long)
#define IOC_REQUEST_SETATTR _IOWR('f', 32, long)
-#define IOC_REQUEST_MAX_NR 32
+#define IOC_REQUEST_CREATE _IOWR('f', 33, long)
+#define IOC_REQUEST_MAX_NR 33
#endif
#include <linux/lustre_idl.h>
#include <linux/lustre_light.h>
+/* packing of MDS records */
+
+void mds_create_pack(struct mds_rec_create *rec, struct inode *inode, char *name, __u32 mode, __u64 id, __u32 uid, __u32 gid, __u64 time)
+{
+ char *tmp = (char *)rec + sizeof(*rec);
+ /* XXX do something about time, uid, gid */
+ rec->cr_reclen =
+ HTON__u32(sizeof(*rec)) + size_round(strlen(name) + 1);
+ rec->cr_opcode = HTON__u32(REINT_CREATE);
+
+ ll_inode2fid(&rec->cr_fid, inode);
+ rec->cr_mode = HTON__u32(mode);
+ rec->cr_id = HTON__u64(id);
+ rec->cr_uid = HTON__u32(uid);
+ rec->cr_gid = HTON__u32(gid);
+ rec->cr_time = HTON__u64(time);
+ rec->cr_namelen = strlen(name);
+ LOGL(name, rec->cr_namelen + 1, tmp);
+}
+
void mds_setattr_pack(struct mds_rec_setattr *rec, struct inode *inode, struct iattr *iattr)
{
- rec->sa_len = HTON__u32(sizeof(*rec));
- rec->sa_opcode = HTON__u32(sizeof(REINT_SETATTR));
+ rec->sa_reclen = HTON__u32(sizeof(*rec));
+ rec->sa_opcode = HTON__u32(REINT_SETATTR);
+
ll_inode2fid(&rec->sa_fid, inode);
rec->sa_valid = HTON__u32(iattr->ia_valid);
rec->sa_mode = HTON__u32(iattr->ia_mode);
rec->sa_attr_flags = HTON__u32(iattr->ia_attr_flags);
}
-void mds_setattr_unpack(struct mds_rec_setattr *rec, struct iattr *attr)
+/* unpacking */
+
+static int mds_update_hdr_unpack(char *buf, int len, struct mds_update_record *r)
{
+ struct mds_update_record_hdr *hdr = (struct mds_update_record_hdr *)buf;
+
+ r->ur_reclen = NTOH__u32(hdr->ur_reclen);
+ if (len < sizeof(*hdr) || len != r->ur_reclen) {
+ printk(__FUNCTION__ "invalid buffer length\n");
+ return -EFAULT;
+ }
+ r->ur_opcode = NTOH__u32(hdr->ur_opcode);
+ return 0;
+}
+
+static int mds_setattr_unpack(char *buf, int len, struct mds_update_record *r)
+{
+
+ struct iattr *attr = &r->ur_iattr;
+ struct mds_rec_setattr *rec = (struct mds_rec_setattr *)buf;
+
+ if (len < sizeof(*rec)) {
+ printk(__FUNCTION__ "invalid buffer length\n");
+ return -EFAULT;
+ }
+
+ r->ur_fid1 = &rec->sa_fid;
attr->ia_valid = NTOH__u32(rec->sa_valid);
attr->ia_mode = NTOH__u32(rec->sa_mode);
attr->ia_uid = NTOH__u32(rec->sa_uid);
attr->ia_mtime = NTOH__u64(rec->sa_mtime);
attr->ia_ctime = NTOH__u64(rec->sa_ctime);
attr->ia_attr_flags = NTOH__u32(rec->sa_attr_flags);
+ return 0;
+}
+
+static int mds_create_unpack(char *buf, int len, struct mds_update_record *r)
+{
+ struct mds_rec_create *rec = (struct mds_rec_create *)buf;
+ char *ptr, *end;
+
+ if (len < sizeof(*rec)) {
+ printk(__FUNCTION__ "invalid buffer length\n");
+ return -EFAULT;
+ }
+
+ ptr = (char *)rec + sizeof(*rec);
+ end = ptr + len - sizeof(*rec);
+
+ r->ur_fid1 = &rec->cr_fid;
+ r->ur_mode = NTOH__u32(rec->cr_mode);
+ r->ur_id = NTOH__u64(rec->cr_id);
+ r->ur_uid = NTOH__u32(rec->cr_uid);
+ r->ur_gid = NTOH__u32(rec->cr_gid);
+ r->ur_time = NTOH__u64(rec->cr_time);
+ r->ur_namelen = NTOH__u64(rec->cr_namelen);
+
+ UNLOGL(r->ur_name, char, r->ur_namelen, ptr, end);
+ return 0;
+}
+
+typedef int (*update_unpacker)(char *, int , struct mds_update_record *);
+
+static update_unpacker mds_unpackers[REINT_MAX + 1] = {
+ [REINT_SETATTR] mds_setattr_unpack,
+ [REINT_CREATE] mds_create_unpack
+};
+
+int mds_update_unpack(char *buf, int len, struct mds_update_record *r)
+{
+ int rc;
+ ENTRY;
+
+ rc = mds_update_hdr_unpack(buf, len, r);
+
+ if (rc) {
+ EXIT;
+ return -EFAULT;
+ }
+
+ if ( r->ur_opcode<0 || r->ur_opcode > REINT_MAX) {
+ EXIT;
+ return EFAULT;
+ }
+
+ rc = mds_unpackers[r->ur_opcode](buf, len, r);
+ EXIT;
+ return rc;
}
kfree(request);
return rc;
}
+
+int mdc_create(struct inode *dir, char *name, int mode, __u64 id,
+ __u32 uid, __u32 gid, __u64 time,
+ struct mds_rep **rep, struct mds_rep_hdr **hdr)
+{
+ int rc;
+ struct mds_request *request;
+ struct mds_rec_create *rec;
+
+ request = mds_prep_req(MDS_REINT, 0, NULL,
+ sizeof(*rec) + size_round(strlen(name)),
+ NULL);
+ if (!request) {
+ printk("mdc_create: cannot pack\n");
+ return -ENOMEM;
+ }
+
+ rec = mds_req_tgt(request->rq_req);
+ mds_create_pack(rec, dir, name, mode, id, uid, gid, time);
+
+ rc = mdc_reint(request);
+
+ if (rep) {
+ *rep = request->rq_rep;
+ }
+ if (hdr) {
+ *hdr = request->rq_rephdr;
+ }
+
+ kfree(request);
+ return rc;
+}
break;
}
+ case IOC_REQUEST_CREATE: {
+ struct inode inode;
+ struct mds_rep_hdr *hdr;
+ struct iattr iattr;
+
+ inode.i_ino = 2;
+ iattr.ia_mode = 040777;
+ iattr.ia_atime = 0;
+ iattr.ia_valid = ATTR_MODE | ATTR_ATIME;
+
+ err = mdc_create(&inode, "foofile", 0100707, 47114711,
+ 11, 47, 0, NULL, &hdr);
+ printk("-- done err %d\n", err);
+ if (!err) {
+ printk("-- status: %d\n", hdr->status);
+ err = hdr->status;
+ }
+ kfree(hdr);
+ break;
+ }
+
default:
err = -EINVAL;
EXIT;
MODULE_DESCRIPTION("Lustre MDS Request Tester v1.0");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(mdc_create);
EXPORT_SYMBOL(mdc_getattr);
EXPORT_SYMBOL(mdc_readpage);
EXPORT_SYMBOL(mdc_setattr);
#include <linux/lustre_mds.h>
#include <linux/obd_class.h>
-// for testing
+// XXX for testing
static struct mds_obd *MDS;
// XXX make this networked!
struct dentry *mds_fid2dentry(struct mds_obd *mds, struct ll_fid *fid, struct vfsmount **mnt)
{
-
- /* iget isn't really right if the inode is currently unallocated!!
- * This should really all be done inside each filesystem
- *
- * ext2fs' read_inode has been strengthed to return a bad_inode if the inode
- * had been deleted.
- *
- * Currently we don't know the generation for parent directory, so a generation
- * of 0 means "accept any"
- */
+ /* stolen from NFS */
struct super_block *sb = mds->mds_sb;
unsigned long ino = fid->id;
//__u32 generation = fid->generation;
if (ino == 0)
return ERR_PTR(-ESTALE);
+
inode = iget(sb, ino);
if (inode == NULL)
return ERR_PTR(-ENOMEM);
|| (generation && inode->i_generation != generation)
) {
/* we didn't find the right inode.. */
- printk("mds_fid2dentry: Inode %lu, Bad count: %d %d or version %u %u\n",
+ printk(__FUNCTION__
+ "bad inode %lu, link: %d ct: %d or version %u/%u\n",
inode->i_ino,
inode->i_nlink, atomic_read(&inode->i_count),
inode->i_generation,
generation);
-
iput(inode);
return ERR_PTR(-ESTALE);
}
+
/* now to find a dentry.
* If possible, get a well-connected one
*/
int mds_reint(struct mds_request *req)
{
- int opc = NTOH__u32(req->rq_req->opcode);
+ int rc;
+ char *buf = mds_req_tgt(req->rq_req);
+ int len = req->rq_req->tgtlen;
+ struct mds_update_record rec;
- switch (opc) {
- case REINT_SETATTR:
- return mds_reint_setattr(req);
- default:
- printk(__FUNCTION__ "opcode %d not handled.\n", opc);
+ rc = mds_update_unpack(buf, len, &rec);
+ if (rc) {
+ printk(__FUNCTION__ ": invalid record\n");
return -EINVAL;
}
+ rc = mds_reint_rec(&rec, req);
return 0;
}
/*
- * linux/mds/handler.c
+ * linux/mds/mds_reint.c
*
- * Lustre Metadata Server (mds) request handler
+ * Lustre Metadata Server (mds) reintegration routines
*
- * Copyright (C) 2001 Cluster File Systems, Inc.
+ * Copyright (C) 2002 Cluster File Systems, Inc.
+ * author: Peter Braam <braam@clusterfs.com>
*
* This code is issued under the GNU General Public License.
* See the file COPYING in this distribution
*
- * by Peter Braam <braam@clusterfs.com>
- *
- * This server is single threaded at present (but can easily be multi threaded).
- *
*/
+// XXX - add transaction sequence numbers
#define EXPORT_SYMTAB
extern struct mds_request *mds_prep_req(int size, int opcode, int namelen, char *name, int tgtlen, char *tgt);
+static int mds_reint_setattr(struct mds_update_record *rec, struct mds_request *req)
+{
+ struct vfsmount *mnt;
+ struct dentry *de;
+
+ de = mds_fid2dentry(req->rq_obd, rec->ur_fid1, &mnt);
+ if (IS_ERR(de)) {
+ req->rq_rephdr->status = -ESTALE;
+ return 0;
+ }
+
+ printk("mds_setattr: ino %ld\n", de->d_inode->i_ino);
+ req->rq_rephdr->status = notify_change(de, &rec->ur_iattr);
+
+ dput(de);
+ EXIT;
+ return 0;
+}
-int mds_reint_setattr(struct mds_request *req)
+static int mds_reint_create(struct mds_update_record *rec,
+ struct mds_request *req)
{
struct vfsmount *mnt;
+ int type = rec->ur_mode & S_IFMT;
struct dentry *de;
- struct mds_rep *rep;
- struct mds_rec_setattr *rec;
- struct iattr attr;
+ struct dentry *dchild;
int rc;
- if (req->rq_req->tgtlen != sizeof(struct mds_rec_setattr) ) {
- EXIT;
- printk("mds: out of memory\n");
- req->rq_status = -EINVAL;
- return -EINVAL;
+ de = mds_fid2dentry(req->rq_obd, rec->ur_fid1, &mnt);
+ if (IS_ERR(de)) {
+ req->rq_rephdr->status = -ESTALE;
+ return 0;
}
- rec = mds_req_tgt(req->rq_req);
+ printk("mds_reint_create: ino %ld\n", de->d_inode->i_ino);
- mds_setattr_unpack(rec, &attr);
- de = mds_fid2dentry(req->rq_obd, &rec->sa_fid, &mnt);
+ dchild = lookup_one_len(rec->ur_name, de, rec->ur_namelen);
+ rc = PTR_ERR(dchild);
+ if (IS_ERR(dchild)) {
+ printk(__FUNCTION__ "child lookup error %d\n", rc);
+ dput(de);
+ req->rq_rephdr->status = -ESTALE;
+ return 0;
+ }
+
+ if (dchild->d_inode) {
+ printk(__FUNCTION__ "child exists (dir %ld, name %s\n",
+ de->d_inode->i_ino, rec->ur_name);
+ dput(de);
+ req->rq_rephdr->status = -ESTALE;
+ return 0;
+ }
+
+ switch (type) {
+ case S_IFREG: {
+ rc = vfs_create(de->d_inode, dchild, rec->ur_mode);
+ break;
+ }
+ case S_IFDIR: {
+ rc = vfs_mkdir(de->d_inode, dchild, rec->ur_mode);
+ break;
+ }
+ case S_IFCHR:
+ case S_IFBLK:
+ case S_IFIFO:
+ case S_IFSOCK: {
+ int rdev = rec->ur_id;
+ rc = vfs_mknod(de->d_inode, dchild, rec->ur_mode, rdev);
+ break;
+ }
+ }
+ req->rq_rephdr->status = rc;
+
+ dput(de);
+ dput(dchild);
+ EXIT;
+ return 0;
+}
+
+typedef int (*mds_reinter)(struct mds_update_record *, struct mds_request*);
+
+static mds_reinter reinters[REINT_MAX+1] = {
+ [REINT_SETATTR] mds_reint_setattr,
+ [REINT_CREATE] mds_reint_create
+};
+
+int mds_reint_rec(struct mds_update_record *rec, struct mds_request *req)
+{
+ int rc;
+
+ if (rec->ur_opcode < 0 || rec->ur_opcode > REINT_MAX) {
+ printk(__FUNCTION__ "opcode %d not valid\n",
+ rec->ur_opcode);
+ return -EINVAL;
+ }
- printk("mds_setattr: ino %ld\n", de->d_inode->i_ino);
-
rc = mds_pack_rep(NULL, 0, NULL, 0, &req->rq_rephdr, &req->rq_rep,
&req->rq_replen, &req->rq_repbuf);
if (rc) {
req->rq_status = -ENOMEM;
return -ENOMEM;
}
-
req->rq_rephdr->seqno = req->rq_reqhdr->seqno;
- rep = req->rq_rep;
- req->rq_rephdr->status = notify_change(de, &attr);
-
- dput(de);
- EXIT;
- return 0;
-}
+ rc = reinters[rec->ur_opcode](rec, req);
+ return rc;
+}
#define IOC_REQUEST_GETATTR _IOWR('f', 30, long)
#define IOC_REQUEST_READPAGE _IOWR('f', 31, long)
#define IOC_REQUEST_SETATTR _IOWR('f', 32, long)
+#define IOC_REQUEST_CREATE _IOWR('f', 33, long)
int main(int argc, char **argv)
{
printf("setattr test... ");
rc = ioctl(fd, IOC_REQUEST_SETATTR, NULL);
printf("result: %d\n", rc);
+
+ printf("create test... ");
+ rc = ioctl(fd, IOC_REQUEST_CREATE, NULL);
+ printf("result: %d\n", rc);
return 0;
}