Whamcloud - gitweb
obdfs/super.c: add call to flush pages when unmounting filesystem
[fs/lustre-release.git] / lustre / obdfs / rw.c
index 1bdbf9e..9bcc915 100644 (file)
@@ -5,7 +5,7 @@
  * Copryright (C) 1999 Stelias Computing Inc, 
  *                (author Peter J. Braam <braam@stelias.com>)
  * Copryright (C) 1999 Seagate Technology Inc.
- */
+*/
 
 
 #include <linux/config.h>
 #include <linux/obdfs.h>
 
 
-int obdfs_flush_reqs(struct list_head *page_list, 
-                    int flush_inode, int check_time);
-
-
 /* SYNCHRONOUS I/O for an inode */
 static int obdfs_brw(int rw, struct inode *inode, struct page *page, int create)
 {
-       obd_count        num_oa = 1;
-       obd_count        oa_bufs = 1;
+       obd_count        num_obdo = 1;
+       obd_count        bufs_per_obdo = 1;
        struct obdo     *oa;
        char            *buf = (char *)page_address(page);
        obd_size         count = PAGE_SIZE;
@@ -58,8 +54,8 @@ static int obdfs_brw(int rw, struct inode *inode, struct page *page, int create)
        }
        obdfs_from_inode(oa, inode);
 
-       err = IOPS(inode, brw)(rw, IID(inode), num_oa, &oa, &oa_bufs, &buf,
-                              &count, &offset, &flags);
+       err = IOPS(inode, brw)(rw, IID(inode), num_obdo, &oa, &bufs_per_obdo,
+                              &buf, &count, &offset, &flags);
 
        if ( !err )
                obdfs_to_inode(inode, oa); /* copy o_blocks to i_blocks */
@@ -90,6 +86,9 @@ int obdfs_readpage(struct dentry *dentry, struct page *page)
 
 static kmem_cache_t *obdfs_pgrq_cachep = NULL;
 
+/* XXX should probably have one of these per superblock */
+static int obdfs_cache_count = 0;
+
 int obdfs_init_pgrqcache(void)
 {
        ENTRY;
@@ -116,16 +115,19 @@ int obdfs_init_pgrqcache(void)
 
 inline void obdfs_pgrq_del(struct obdfs_pgrq *pgrq)
 {
-               list_del(&pgrq->rq_plist);
-               kmem_cache_free(obdfs_pgrq_cachep, pgrq);
+       obdfs_cache_count--;
+       CDEBUG(D_INODE, "deleting page %p from list [count %d]\n",
+              pgrq->rq_page, obdfs_cache_count);
+       list_del(&pgrq->rq_plist);
+       kmem_cache_free(obdfs_pgrq_cachep, pgrq);
 }
 
 void obdfs_cleanup_pgrqcache(void)
 {
        ENTRY;
        if (obdfs_pgrq_cachep != NULL) {
-               CDEBUG(D_INODE, "destroying obdfs_pgrqcache at %p\n",
-                      obdfs_pgrq_cachep);
+               CDEBUG(D_INODE, "destroying obdfs_pgrqcache at %p, count %d\n",
+                      obdfs_pgrq_cachep, obdfs_cache_count);
                if (kmem_cache_destroy(obdfs_pgrq_cachep))
                        printk(KERN_INFO "obd_cleanup_pgrqcache: unable to free all of cache\n");
        } else
@@ -138,6 +140,7 @@ void obdfs_cleanup_pgrqcache(void)
 /*
  * Find a specific page in the page cache.  If it is found, we return
  * the write request struct associated with it, if not found return NULL.
+ * Called with the list lock held.
  */
 static struct obdfs_pgrq *
 obdfs_find_in_page_list(struct inode *inode, struct page *page)
@@ -146,7 +149,10 @@ obdfs_find_in_page_list(struct inode *inode, struct page *page)
        struct list_head *tmp;
 
        ENTRY;
+
        CDEBUG(D_INODE, "looking for inode %ld page %p\n", inode->i_ino, page);
+       OIDEBUG(inode);
+
        if (list_empty(page_list)) {
                CDEBUG(D_INODE, "empty list\n");
                EXIT;
@@ -157,7 +163,6 @@ obdfs_find_in_page_list(struct inode *inode, struct page *page)
                struct obdfs_pgrq *pgrq;
 
                pgrq = list_entry(tmp, struct obdfs_pgrq, rq_plist);
-               CDEBUG(D_INODE, "checking page %p\n", pgrq->rq_page);
                if (pgrq->rq_page == page) {
                        CDEBUG(D_INODE, "found page %p in list\n", page);
                        EXIT;
@@ -170,25 +175,75 @@ obdfs_find_in_page_list(struct inode *inode, struct page *page)
 } /* obdfs_find_in_page_list */
 
 
-/* call and free pages from Linux page cache */
-int obdfs_do_vec_wr(struct super_block *sb, obd_count num_io,
+/* called with the list lock held */
+static struct page* obdfs_find_page_index(struct inode *inode,
+                                         unsigned long index)
+{
+       struct list_head *page_list = obdfs_iplist(inode);
+       struct list_head *tmp;
+       struct page *page;
+
+       ENTRY;
+
+       CDEBUG(D_INODE, "looking for inode %ld pageindex %ld\n",
+              inode->i_ino, index);
+       OIDEBUG(inode);
+
+       if (list_empty(page_list)) {
+               EXIT;
+               return NULL;
+       }
+       tmp = page_list;
+       while ( (tmp = tmp->next) != page_list ) {
+               struct obdfs_pgrq *pgrq;
+
+               pgrq = list_entry(tmp, struct obdfs_pgrq, rq_plist);
+               page = pgrq->rq_page;
+               if (index == page->index) {
+                       CDEBUG(D_INODE,
+                              "INDEX SEARCH found page %p, index %ld\n",
+                              page, index);
+                       EXIT;
+                       return page;
+               }
+       } 
+
+       EXIT;
+       return NULL;
+} /* obdfs_find_page_index */
+
+
+/* call and free pages from Linux page cache: called with io lock on inodes */
+int obdfs_do_vec_wr(struct inode **inodes, obd_count num_io,
                    obd_count num_obdos, struct obdo **obdos,
                    obd_count *oa_bufs, struct page **pages, char **bufs,
                    obd_size *counts, obd_off *offsets, obd_flag *flags)
 {
+       struct super_block *sb = inodes[0]->i_sb;
        struct obdfs_sb_info *sbi = (struct obdfs_sb_info *)&sb->u.generic_sbp;
        int err;
 
        ENTRY;
-       CDEBUG(D_INODE, "writing %d pages, %d obdos in vector\n",
+       CDEBUG(D_INODE, "writing %d page(s), %d obdo(s) in vector\n",
               num_io, num_obdos);
        err = OPS(sb, brw)(WRITE, &sbi->osi_conn, num_obdos, obdos, oa_bufs,
                                bufs, counts, offsets, flags);
 
-       do {
-               put_page(pages[--num_io]);
-       } while ( num_io > 0 );
+       /* release the pages from the page cache */
+       while ( num_io > 0 ) {
+               num_io--;
+               CDEBUG(D_INODE, "calling put_page for %p, index %ld\n",
+                      pages[num_io], pages[num_io]->index);
+               put_page(pages[num_io]);
+       }
 
+       while ( num_obdos > 0) {
+               num_obdos--;
+               CDEBUG(D_INODE, "copy/free obdo %ld\n",
+                      (long)obdos[num_obdos]->o_id);
+               obdfs_to_inode(inodes[num_obdos], obdos[num_obdos]);
+               obdo_free(obdos[num_obdos]);
+       }
        EXIT;
        return err;
 }
@@ -200,43 +255,49 @@ int obdfs_do_vec_wr(struct super_block *sb, obd_count num_io,
  */
 static int obdfs_add_page_to_cache(struct inode *inode, struct page *page)
 {
-       struct obdfs_pgrq *pgrq;
+       int res = 0;
 
        ENTRY;
-       pgrq = kmem_cache_alloc(obdfs_pgrq_cachep, SLAB_KERNEL);
-       CDEBUG(D_INODE, "adding inode %ld page %p, pgrq: %p\n",
-              inode->i_ino, page, pgrq);
-       if (!pgrq) {
-               EXIT;
-               return -ENOMEM;
-       }
-       memset(pgrq, 0, sizeof(*pgrq)); 
-
-       pgrq->rq_page = page;
-
-       get_page(pgrq->rq_page);
 
        /* If this page isn't already in the inode page list, add it */
+       obd_down(&obdfs_i2sbi(inode)->osi_list_mutex);
        if ( !obdfs_find_in_page_list(inode, page) ) {
-               CDEBUG(D_INODE, "adding page %p to inode list %p\n", page,
-                      obdfs_iplist(inode));
+               struct obdfs_pgrq *pgrq;
+               pgrq = kmem_cache_alloc(obdfs_pgrq_cachep, SLAB_KERNEL);
+               CDEBUG(D_INODE, "adding inode %ld page %p, pgrq: %p, cache count [%d]\n",
+                      inode->i_ino, page, pgrq, obdfs_cache_count);
+               if (!pgrq) {
+                       EXIT;
+                       obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
+                       return -ENOMEM;
+               }
+               memset(pgrq, 0, sizeof(*pgrq)); 
+               
+               pgrq->rq_page = page;
+               get_page(pgrq->rq_page);
                list_add(&pgrq->rq_plist, obdfs_iplist(inode));
+               obdfs_cache_count++;
        }
 
-       /* If inode isn't already on the superblock inodes list, add it */
+       /* If inode isn't already on the superblock inodes list, add it,
+        * and increase ref count on inode so it doesn't disappear on us.
+        */
        if ( list_empty(obdfs_islist(inode)) ) {
-               CDEBUG(D_INODE, "adding inode %p to superblock list %p\n",
-                      obdfs_islist(inode), obdfs_islist(inode));
+               iget(inode->i_sb, inode->i_ino);
+               CDEBUG(D_INODE, "adding inode %ld to superblock list %p\n",
+                      inode->i_ino, obdfs_slist(inode));
                list_add(obdfs_islist(inode), obdfs_slist(inode));
        }
 
-
-       EXIT;
        /* XXX For testing purposes, we write out the page here.
         *     In the future, a flush daemon will write out the page.
-       return 0;
+       res = obdfs_flush_reqs(obdfs_slist(inode), 0);
+       obdfs_flush_dirty_pages(1);
         */
-       return obdfs_flush_reqs(obdfs_slist(inode), 0, 0);
+       obd_up(&obdfs_i2sbi(inode)->osi_list_mutex);
+
+       EXIT;
+       return res;
 } /* obdfs_add_page_to_cache */
 
 
@@ -246,15 +307,17 @@ int obdfs_do_writepage(struct inode *inode, struct page *page, int sync)
        int err;
 
        ENTRY;
-       PDEBUG(page, "WRITEPAGE");
+       /* PDEBUG(page, "WRITEPAGE"); */
        if ( sync )
                err = obdfs_brw(WRITE, inode, page, 1);
-       else
+       else {
                err = obdfs_add_page_to_cache(inode, page);
+               CDEBUG(D_IOCTL, "DO_WR ino: %ld, page %p, err %d, uptodata %d\n", inode->i_ino, page, err, Page_Uptodate(page));
+       }
                
        if ( !err )
                SetPageUptodate(page);
-       PDEBUG(page,"WRITEPAGE");
+       /* PDEBUG(page,"WRITEPAGE"); */
        EXIT;
        return err;
 } /* obdfs_do_writepage */
@@ -303,16 +366,18 @@ int obdfs_write_one_page(struct file *file, struct page *page,
 } /* obdfs_write_one_page */
 
 /* 
-   return an up to date page:
-    - if locked is true then is returned locked
-    - if create is true the corresponding disk blocks are created 
-    - page is held, i.e. caller must release the page
-
-   modeled on NFS code.
-*/
-struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create, int locked)
+ * return an up to date page:
+ *  - if locked is true then is returned locked
+ *  - if create is true the corresponding disk blocks are created 
+ *  - page is held, i.e. caller must release the page
+ *
+ * modeled on NFS code.
+ */
+struct page *obdfs_getpage(struct inode *inode, unsigned long offset,
+                          int create, int locked)
 {
        struct page *page_cache;
+       int index;
        struct page ** hash;
        struct page * page;
        int err;
@@ -320,8 +385,11 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create
        ENTRY;
 
        offset = offset & PAGE_CACHE_MASK;
-       CDEBUG(D_INODE, "\n");
-       
+       CDEBUG(D_INODE, "ino: %ld, offset %ld, create %d, locked %d\n",
+              inode->i_ino, offset, create, locked);
+       index = offset >> PAGE_CACHE_SHIFT;
+
+
        page = NULL;
        page_cache = page_cache_alloc();
        if ( ! page_cache ) {
@@ -330,8 +398,8 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create
        }
        CDEBUG(D_INODE, "page_cache %p\n", page_cache);
 
-       hash = page_hash(&inode->i_data, offset);
-       page = grab_cache_page(&inode->i_data, offset);
+       hash = page_hash(&inode->i_data, index);
+       page = grab_cache_page(&inode->i_data, index);
 
        /* Yuck, no page */
        if (! page) {
@@ -349,6 +417,12 @@ struct page *obdfs_getpage(struct inode *inode, unsigned long offset, int create
                return page;
        } 
 
+
+       if ( obdfs_find_page_index(inode, index) ) {
+               CDEBUG(D_INODE, "OVERWRITE: found dirty page %p, index %ld\n",
+                      page, page->index);
+       }
+
        err = obdfs_brw(READ, inode, page, create);
 
        if ( err ) {