/* * linux/mds/handler.c * * Lustre Metadata Server (mds) request handler * * Copyright (C) 2001 Cluster File Systems, Inc. * * This code is issued under the GNU General Public License. * See the file COPYING in this distribution * * by Peter Braam * * This server is single threaded at present (but can easily be multi threaded). * */ #define EXPORT_SYMTAB #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for testing static struct mds_obd *MDS; // for testing static int mds_queue_req(struct mds_request *req) { if (!MDS) { EXIT; return -1; } list_add(&req->rq_list, &MDS->mds_reqs); init_waitqueue_head(&req->rq_wait_for_mds_rep); req->rq_obd = MDS; wake_up(&MDS->mds_waitq); printk("-- sleeping\n"); interruptible_sleep_on(&req->rq_wait_for_mds_rep); printk("-- done\n"); return 0; } static struct dentry *mds_fid2dentry(struct mds_obd *mds, struct lustre_fid *fid) { struct dentry *de; struct inode *inode; inode = iget(mds->mds_sb, fid->id); if (!inode) { EXIT; } de = d_alloc_root(inode); if (!de) { iput(inode); EXIT; return NULL; } de->d_inode = inode; return de; } int mds_getattr(struct mds_request *req) { struct dentry *de = mds_fid2dentry(req->rq_obd, &req->rq_req->fid1); struct inode *inode; struct mds_rep *rep; int rc; rc = mds_pack_rep(NULL, 0, NULL, 0, &req->rq_rephdr, &req->rq_rep, &req->rq_replen, &req->rq_repbuf); if (rc) { EXIT; printk("mds: out of memory\n"); req->rq_status = -ENOMEM; return -ENOMEM; } req->rq_rephdr->seqno = req->rq_reqhdr->seqno; rep = req->rq_rep; if (!de) { EXIT; req->rq_rephdr->status = -ENOENT; return 0; } inode = de->d_inode; rep->atime = inode->i_atime; rep->ctime = inode->i_ctime; rep->mtime = inode->i_mtime; rep->uid = inode->i_uid; rep->gid = inode->i_gid; rep->size = inode->i_size; rep->mode = inode->i_mode; dput(de); return 0; } int mds_reply(struct mds_request *req) { ENTRY; kfree(req->rq_reqbuf); req->rq_reqbuf = NULL; wake_up_interruptible(&req->rq_wait_for_mds_rep); EXIT; return 0; } int mds_error(struct mds_request *req) { struct mds_rep_hdr *hdr; ENTRY; hdr = kmalloc(sizeof(*hdr), GFP_KERNEL); if (!hdr) { EXIT; return -ENOMEM; } memset(hdr, 0, sizeof(*hdr)); hdr->seqno = req->rq_reqhdr->seqno; hdr->status = req->rq_status; hdr->type = MDS_TYPE_ERR; req->rq_repbuf = (char *)hdr; EXIT; return mds_reply(req); } //int mds_handle(struct mds_conn *conn, int len, char *buf) int mds_handle(struct mds_request *req) { int rc; struct mds_req_hdr *hdr; ENTRY; hdr = (struct mds_req_hdr *)req->rq_reqbuf; if (NTOH__u32(hdr->type) != MDS_TYPE_REQ) { printk("lustre_mds: wrong packet type sent %d\n", NTOH__u32(hdr->type)); rc = -EINVAL; goto out; } rc = mds_unpack_req(req->rq_reqbuf, req->rq_reqlen, &req->rq_reqhdr, &req->rq_req); if (rc) { printk("lustre_mds: Invalid request\n"); EXIT; goto out; } switch (req->rq_reqhdr->opc) { case MDS_GETATTR: CDEBUG(D_INODE, "getattr\n"); rc = mds_getattr(req); break; case MDS_OPEN: return mds_getattr(req); case MDS_SETATTR: return mds_getattr(req); case MDS_CREATE: return mds_getattr(req); case MDS_MKDIR: return mds_getattr(req); case MDS_RMDIR: return mds_getattr(req); case MDS_SYMLINK: return mds_getattr(req); case MDS_LINK: return mds_getattr(req); case MDS_MKNOD: return mds_getattr(req); case MDS_UNLINK: return mds_getattr(req); case MDS_RENAME: return mds_getattr(req); default: return mds_error(req); } out: if (rc) { printk("mds: processing error %d\n", rc); mds_error(req); } else { CDEBUG(D_INODE, "sending reply\n"); mds_reply(req); } return 0; } static void mds_timer_run(unsigned long __data) { struct task_struct * p = (struct task_struct *) __data; wake_up_process(p); } int mds_main(void *arg) { struct mds_obd *mds = (struct mds_obd *) arg; struct timer_list timer; lock_kernel(); daemonize(); spin_lock_irq(¤t->sigmask_lock); sigfillset(¤t->blocked); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); sprintf(current->comm, "lustre_mds"); /* Set up an interval timer which can be used to trigger a wakeup after the interval expires */ init_timer(&timer); timer.data = (unsigned long) current; timer.function = mds_timer_run; mds->mds_timer = &timer; /* Record that the thread is running */ mds->mds_thread = current; wake_up(&mds->mds_done_waitq); printk(KERN_INFO "lustre_mds starting. Commit interval %d seconds\n", mds->mds_interval / HZ); /* XXX maintain a list of all managed devices: insert here */ /* And now, wait forever for commit wakeup events. */ while (1) { struct mds_request *request; int rc; if (mds->mds_flags & MDS_UNMOUNT) break; wake_up(&mds->mds_done_waitq); interruptible_sleep_on(&mds->mds_waitq); CDEBUG(D_INODE, "lustre_mds wakes\n"); CDEBUG(D_INODE, "pick up req here and continue\n"); if (list_empty(&mds->mds_reqs)) { CDEBUG(D_INODE, "woke because of timer\n"); } else { request = list_entry(mds->mds_reqs.next, struct mds_request, rq_list); list_del(&request->rq_list); rc = mds_handle(request); } } del_timer_sync(mds->mds_timer); /* XXX maintain a list of all managed devices: cleanup here */ mds->mds_thread = NULL; wake_up(&mds->mds_done_waitq); printk("lustre_mds: exiting\n"); return 0; } static void mds_stop_srv_thread(struct mds_obd *mds) { mds->mds_flags |= MDS_UNMOUNT; while (mds->mds_thread) { wake_up(&mds->mds_waitq); sleep_on(&mds->mds_done_waitq); } } static void mds_start_srv_thread(struct mds_obd *mds) { init_waitqueue_head(&mds->mds_waitq); init_waitqueue_head(&mds->mds_done_waitq); kernel_thread(mds_main, (void *)mds, CLONE_VM | CLONE_FS | CLONE_FILES); while (!mds->mds_thread) sleep_on(&mds->mds_done_waitq); } /* mount the file system (secretly) */ static int mds_setup(struct obd_device *obddev, obd_count len, void *buf) { struct obd_ioctl_data* data = buf; struct mds_obd *mds = &obddev->u.mds; struct vfsmount *mnt; int err; ENTRY; mnt = do_kern_mount(data->ioc_inlbuf2, 0, data->ioc_inlbuf1, NULL); err = PTR_ERR(mnt); if (IS_ERR(mnt)) { EXIT; return err; } mds->mds_sb = mnt->mnt_root->d_inode->i_sb; if (!obddev->u.mds.mds_sb) { EXIT; return -ENODEV; } INIT_LIST_HEAD(&mds->mds_reqs); mds->mds_thread = NULL; mds->mds_flags = 0; mds->mds_interval = 3 * HZ; mds->mds_vfsmnt = mnt; obddev->u.mds.mds_fstype = strdup(data->ioc_inlbuf2); mds->mds_ctxt.pwdmnt = mnt; mds->mds_ctxt.pwd = mnt->mnt_root; mds->mds_ctxt.fs = KERNEL_DS; MDS = mds; spin_lock_init(&obddev->u.mds.fo_lock); mds_start_srv_thread(mds); MOD_INC_USE_COUNT; EXIT; return 0; } static int mds_cleanup(struct obd_device * obddev) { struct super_block *sb; struct mds_obd *mds = &obddev->u.mds; ENTRY; if ( !(obddev->obd_flags & OBD_SET_UP) ) { EXIT; return 0; } if ( !list_empty(&obddev->obd_gen_clients) ) { printk(KERN_WARNING __FUNCTION__ ": still has clients!\n"); EXIT; return -EBUSY; } MDS = NULL; mds_stop_srv_thread(mds); sb = mds->mds_sb; if (!mds->mds_sb){ EXIT; return 0; } if (!list_empty(&mds->mds_reqs)) { // XXX reply with errors and clean up CDEBUG(D_INODE, "Request list not empty!\n"); } unlock_kernel(); mntput(mds->mds_vfsmnt); mds->mds_sb = 0; kfree(mds->mds_fstype); lock_kernel(); MOD_DEC_USE_COUNT; EXIT; return 0; } /* use obd ops to offer management infrastructure */ static struct obd_ops mds_obd_ops = { o_setup: mds_setup, o_cleanup: mds_cleanup, }; static int __init mds_init(void) { obd_register_type(&mds_obd_ops, LUSTRE_MDS_NAME); return 0; } static void __exit mds_exit(void) { obd_unregister_type(LUSTRE_MDS_NAME); } MODULE_AUTHOR("Peter J. Braam "); MODULE_DESCRIPTION("Lustre Metadata Server (MDS) v0.01"); MODULE_LICENSE("GPL"); // for testing (maybe this stays) EXPORT_SYMBOL(mds_queue_req); module_init(mds_init); module_exit(mds_exit);