Whamcloud - gitweb
Changes for file creation and small fixes.
[fs/lustre-release.git] / lustre / mds / handler.c
index 1e40b3e..fe93fd7 100644 (file)
@@ -25,6 +25,7 @@
 #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>
@@ -32,7 +33,7 @@
 #include <linux/lustre_mds.h>
 #include <linux/obd_class.h>
 
-// for testing
+// XXX for testing
 static struct mds_obd *MDS;
 
 // XXX make this networked!  
@@ -69,6 +70,23 @@ static int mds_queue_req(struct mds_request *req)
        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)
 {
@@ -116,32 +134,77 @@ int mds_error(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;
@@ -165,6 +228,7 @@ int mds_getattr(struct mds_request *req)
        }
 
        inode = de->d_inode;
+       rep->ino = inode->i_ino;
        rep->atime = inode->i_atime;
        rep->ctime = inode->i_ctime;
        rep->mtime = inode->i_mtime;
@@ -172,11 +236,79 @@ int mds_getattr(struct mds_request *req)
        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)
@@ -210,35 +342,15 @@ 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);
@@ -386,7 +498,7 @@ static int mds_setup(struct obd_device *obddev, obd_count len,
        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);