#include <linux/ext2_fs.h>
#include <linux/quotaops.h>
#include <asm/unistd.h>
+#include <asm/uaccess.h>
#include <linux/obd_support.h>
#include <linux/obd.h>
#include <linux/lustre_lib.h>
#include <linux/lustre_mds.h>
#include <linux/obd_class.h>
-// for testing
+// XXX for testing
static struct mds_obd *MDS;
// XXX make this networked!
return 0;
}
+/* XXX do this over the net */
+int mds_sendpage(struct mds_request *req, struct file *file,
+ __u64 offset, struct niobuf *dst)
+{
+ int rc;
+ mm_segment_t oldfs = get_fs();
+ /* dst->addr is a user address, but in a different task! */
+ set_fs(KERNEL_DS);
+ rc = generic_file_read(file, (char *)(long)dst->addr,
+ PAGE_SIZE, &offset);
+ set_fs(oldfs);
+
+ if (rc != PAGE_SIZE)
+ return -EIO;
+ return 0;
+}
+
/* XXX replace with networking code */
int mds_reply(struct mds_request *req)
{
return mds_reply(req);
}
-
-
-static struct dentry *mds_fid2dentry(struct mds_obd *mds, struct lustre_fid *fid)
+struct dentry *mds_fid2dentry(struct mds_obd *mds, struct ll_fid *fid, struct vfsmount **mnt)
{
- struct dentry *de;
+ /* stolen from NFS */
+ struct super_block *sb = mds->mds_sb;
+ unsigned long ino = fid->id;
+ //__u32 generation = fid->generation;
+ __u32 generation = 0;
struct inode *inode;
+ struct list_head *lp;
+ struct dentry *result;
- inode = iget(mds->mds_sb, fid->id);
- if (!inode) {
- EXIT;
+ if (mnt) {
+ *mnt = mntget(mds->mds_vfsmnt);
}
- de = d_alloc_root(inode);
- if (!de) {
+ if (ino == 0)
+ return ERR_PTR(-ESTALE);
+
+ inode = iget(sb, ino);
+ if (inode == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ printk("--> mds_fid2dentry: sb %p\n", inode->i_sb);
+
+ if (is_bad_inode(inode)
+ || (generation && inode->i_generation != generation)
+ ) {
+ /* we didn't find the right inode.. */
+ 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);
- EXIT;
- return NULL;
+ return ERR_PTR(-ESTALE);
+ }
+
+ /* now to find a dentry.
+ * If possible, get a well-connected one
+ */
+ spin_lock(&dcache_lock);
+ for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) {
+ result = list_entry(lp,struct dentry, d_alias);
+ if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
+ dget_locked(result);
+ result->d_vfs_flags |= DCACHE_REFERENCED;
+ spin_unlock(&dcache_lock);
+ iput(inode);
+ return result;
+ }
}
+ spin_unlock(&dcache_lock);
+ result = d_alloc_root(inode);
+ if (result == NULL) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+ result->d_flags |= DCACHE_NFSD_DISCONNECTED;
+ return result;
+}
- de->d_inode = inode;
- return de;
+static inline void mds_get_objid(struct inode *inode, __u64 *id)
+{
+ memcpy(id, &inode->u.ext2_i.i_data, sizeof(*id));
}
int mds_getattr(struct mds_request *req)
{
- struct dentry *de = mds_fid2dentry(req->rq_obd, &req->rq_req->fid1);
+ struct dentry *de = mds_fid2dentry(req->rq_obd, &req->rq_req->fid1,
+ NULL);
struct inode *inode;
struct mds_rep *rep;
int rc;
}
inode = de->d_inode;
+ rep->ino = inode->i_ino;
rep->atime = inode->i_atime;
rep->ctime = inode->i_ctime;
rep->mtime = inode->i_mtime;
rep->gid = inode->i_gid;
rep->size = inode->i_size;
rep->mode = inode->i_mode;
-
+ rep->nlink = inode->i_nlink;
+ rep->valid = ~0;
+ mds_get_objid(inode, &rep->objid);
dput(de);
return 0;
}
+int mds_readpage(struct mds_request *req)
+{
+ struct vfsmount *mnt;
+ struct dentry *de = mds_fid2dentry(req->rq_obd, &req->rq_req->fid1,
+ &mnt);
+ struct file *file;
+ struct niobuf *niobuf;
+ struct mds_rep *rep;
+ int rc;
+
+ printk("mds_readpage: 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) {
+ 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 (IS_ERR(de)) {
+ EXIT;
+ req->rq_rephdr->status = PTR_ERR(de);
+ return 0;
+ }
+
+ file = dentry_open(de, mnt, O_RDONLY | O_LARGEFILE);
+ /* note: in case of an error, dentry_open puts dentry */
+ if (IS_ERR(file)) {
+ EXIT;
+ req->rq_rephdr->status = PTR_ERR(file);
+ return 0;
+ }
+
+ niobuf = mds_req_tgt(req->rq_req);
+
+ /* to make this asynchronous make sure that the handling function
+ doesn't send a reply when this function completes. Instead a
+ callback function would send the reply */
+ rc = mds_sendpage(req, file, req->rq_req->size, niobuf);
+
+ filp_close(file, 0);
+ req->rq_rephdr->status = rc;
+ EXIT;
+ return 0;
+}
+
+int mds_reint(struct mds_request *req)
+{
+ int rc;
+ char *buf = mds_req_tgt(req->rq_req);
+ int len = req->rq_req->tgtlen;
+ struct mds_update_record rec;
+
+ rc = mds_update_unpack(buf, len, &rec);
+ if (rc) {
+ printk(__FUNCTION__ ": invalid record\n");
+ return -EINVAL;
+ }
+
+ rc = mds_reint_rec(&rec, req);
+ return 0;
+}
//int mds_handle(struct mds_conn *conn, int len, char *buf)
int mds_handle(struct mds_request *req)
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_READPAGE:
+ CDEBUG(D_INODE, "readpage\n");
+ rc = mds_readpage(req);
+ break;
- case MDS_RENAME:
- return mds_getattr(req);
+ case MDS_REINT:
+ CDEBUG(D_INODE, "reint\n");
+ rc = mds_reint(req);
+ break;
default:
return mds_error(req);
mds->mds_ctxt.fs = KERNEL_DS;
MDS = mds;
- spin_lock_init(&obddev->u.mds.fo_lock);
+ spin_lock_init(&obddev->u.mds.mds_lock);
mds_start_srv_thread(mds);