Whamcloud - gitweb
b=3869,1742
[fs/lustre-release.git] / lustre / obdfilter / filter_io_26.c
index b312f8b..95f8263 100644 (file)
@@ -37,9 +37,6 @@
 
 #warning "implement writeback mode -bzzz"
 
-int ext3_map_inode_page(struct inode *inode, struct page *page,
-                        unsigned long *blocks, int *created, int create);
-
 /* 512byte block min */
 #define MAX_BLOCKS_PER_PAGE (PAGE_SIZE / 512)
 struct dio_request {
@@ -77,33 +74,63 @@ static int can_be_merged(struct bio *bio, sector_t sector)
         return bio->bi_sector + size == sector ? 1 : 0;
 }
 
-int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
-                          struct obd_ioobj *obj, int niocount,
-                          struct niobuf_local *res, struct obd_trans_info *oti)
+/* See if there are unallocated parts in given file region */
+static int filter_range_is_mapped(struct inode *inode, obd_size offset, int len)
 {
-        struct obd_device *obd = exp->exp_obd;
-        struct obd_run_ctxt saved;
+        sector_t (*fs_bmap)(struct address_space *, sector_t) =
+                inode->i_mapping->a_ops->bmap;
+        int j;
+
+        /* We can't know if we are overwriting or not */
+        if (fs_bmap == NULL)
+                return 0;
+
+        offset >>= inode->i_blkbits;
+        len >>= inode->i_blkbits;
+
+        for (j = 0; j <= len; j++)
+                if (fs_bmap(inode->i_mapping, offset + j) == 0)
+                        return 0;
+
+        return 1;
+}
+
+int filter_commitrw_write(struct obd_export *exp, struct obdo *oa,
+                          int objcount, struct obd_ioobj *obj, int niocount,
+                          struct niobuf_local *res, struct obd_trans_info *oti,
+                          int rc)
+{
+        struct bio *bio = NULL;
+        int blocks_per_page, err;
         struct niobuf_local *lnb;
+        struct lvfs_run_ctxt saved;
         struct fsfilt_objinfo fso;
-        struct iattr iattr = { .ia_valid = ATTR_SIZE, .ia_size = 0, };
+        struct iattr iattr = { 0 };
         struct inode *inode = NULL;
-        int rc = 0, i, k, cleanup_phase = 0, err;
-        unsigned long now = jiffies; /* DEBUGGING OST TIMEOUTS */
-        int blocks_per_page;
-        struct dio_request *dreq;
-        struct bio *bio = NULL;
+        unsigned long now = jiffies;
+        int i, k, cleanup_phase = 0;
+
+        struct dio_request *dreq = NULL;
+        struct obd_device *obd = exp->exp_obd;
+
         ENTRY;
+
         LASSERT(oti != NULL);
         LASSERT(objcount == 1);
         LASSERT(current->journal_info == NULL);
 
+        if (rc != 0)
+                GOTO(cleanup, rc);
+
         inode = res->dentry->d_inode;
         blocks_per_page = PAGE_SIZE >> inode->i_blkbits;
         LASSERT(blocks_per_page <= MAX_BLOCKS_PER_PAGE);
 
         OBD_ALLOC(dreq, sizeof(*dreq));
+
         if (dreq == NULL)
                 RETURN(-ENOMEM);
+
         dreq->bio_list = NULL;
         init_waitqueue_head(&dreq->wait);
         atomic_set(&dreq->numreqs, 0);
@@ -113,10 +140,14 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
         fso.fso_dentry = res->dentry;
         fso.fso_bufcnt = obj->ioo_bufcnt;
 
-        push_ctxt(&saved, &obd->obd_ctxt, NULL);
+        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
         cleanup_phase = 2;
 
-        oti->oti_handle = fsfilt_brw_start(obd, objcount, &fso, niocount, oti);
+        generic_osync_inode(inode, inode->i_mapping, OSYNC_DATA|OSYNC_METADATA);
+
+        oti->oti_handle = fsfilt_brw_start(obd, objcount, &fso,
+                                           niocount, res, oti);
+        
         if (IS_ERR(oti->oti_handle)) {
                 rc = PTR_ERR(oti->oti_handle);
                 CDEBUG(rc == -ENOSPC ? D_INODE : D_ERROR,
@@ -128,15 +159,27 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
         if (time_after(jiffies, now + 15 * HZ))
                 CERROR("slow brw_start %lus\n", (jiffies - now) / HZ);
 
+        iattr_from_obdo(&iattr,oa,OBD_MD_FLATIME|OBD_MD_FLMTIME|OBD_MD_FLCTIME);
         for (i = 0, lnb = res; i < obj->ioo_bufcnt; i++, lnb++) {
                 loff_t this_size;
                 sector_t sector;
+                struct page *pages[1];
                 int offs;
 
+                /* If overwriting an existing block, we don't need a grant */
+                if (!(lnb->flags & OBD_BRW_GRANTED) && lnb->rc == -ENOSPC &&
+                    filter_range_is_mapped(inode, lnb->offset, lnb->len))
+                        lnb->rc = 0;
+
+                if (lnb->rc) /* ENOSPC, network RPC error, etc. */ 
+                        continue;
+
                 /* get block number for next page */
-                rc = ext3_map_inode_page(inode, lnb->page, dreq->blocks,
-                                                dreq->created, 1);
-                if (rc)
+                pages[0] = lnb->page;
+                rc = fsfilt_map_inode_pages(obd, inode, pages, 1, 
+                                            dreq->blocks, dreq->created, 1,
+                                            NULL);
+                if (rc != 0)
                         GOTO(cleanup, rc);
 
                 for (k = 0; k < blocks_per_page; k++) {
@@ -144,7 +187,7 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
                         offs = k * inode->i_sb->s_blocksize;
 
                         if (!bio || !can_be_merged(bio, sector) ||
-                            !bio_add_page(bio, lnb->page, lnb->len, offs)) {
+                            !bio_add_page(bio, lnb->page, PAGE_SIZE, offs)) {
                                 if (bio) {
                                         atomic_inc(&dreq->numreqs);
                                         submit_bio(WRITE, bio);
@@ -157,22 +200,22 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
                                 bio->bi_end_io = dio_complete_routine;
                                 bio->bi_private = dreq;
 
-                                if (!bio_add_page(bio, lnb->page, lnb->len, 0))
+                                if (!bio_add_page(bio, lnb->page, PAGE_SIZE, 
+                                                  offs))
                                         LBUG();
                         }
                 }
 
-                /* We expect these pages to be in offset order, but we'll
+                /* we expect these pages to be in offset order, but we'll
                  * be forgiving */
                 this_size = lnb->offset + lnb->len;
                 if (this_size > iattr.ia_size)
                         iattr.ia_size = this_size;
         }
 
-#warning This probably needs filemap_fdatasync() like filter_io_24 (bug 2366)
         if (bio) {
                 atomic_inc(&dreq->numreqs);
-                submit_bio(WRITE, bio);
+                fsfilt_send_bio(obd, inode, bio);
         }
 
         /* time to wait for I/O completion */
@@ -185,45 +228,49 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
                 bio_put(bio);
         }
 
-        if (rc == 0) {
-                down(&inode->i_sem);
-                inode_update_time(inode, 1);
-                if (iattr.ia_size > inode->i_size) {
-                        CDEBUG(D_INFO, "setting i_size to "LPU64"\n",
-                               iattr.ia_size);
-                        fsfilt_setattr(obd, res->dentry, oti->oti_handle,
-                                       &iattr, 0);
-                }
-                up(&inode->i_sem);
+        down(&inode->i_sem);
+        if (iattr.ia_size > inode->i_size) {
+                CDEBUG(D_INFO, "setting i_size to "LPU64"\n",
+                       iattr.ia_size);
+                       
+                iattr.ia_valid |= ATTR_SIZE;
+                       
+                fsfilt_setattr(obd, res->dentry, oti->oti_handle,
+                               &iattr, 0);
         }
+        up(&inode->i_sem);
 
         if (time_after(jiffies, now + 15 * HZ))
                 CERROR("slow direct_io %lus\n", (jiffies - now) / HZ);
 
         rc = filter_finish_transno(exp, oti, rc);
+
         err = fsfilt_commit(obd, inode, oti->oti_handle, obd_sync_filter);
         if (err)
                 rc = err;
+
         if (obd_sync_filter)
                 LASSERT(oti->oti_transno <= obd->obd_last_committed);
+
         if (time_after(jiffies, now + 15 * HZ))
                 CERROR("slow commitrw commit %lus\n", (jiffies - now) / HZ);
 
 cleanup:
+        filter_grant_commit(exp, niocount, res);
+
         switch (cleanup_phase) {
         case 2:
-                pop_ctxt(&saved, &obd->obd_ctxt, NULL);
+                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                 LASSERT(current->journal_info == NULL);
         case 1:
                 OBD_FREE(dreq, sizeof(*dreq));
         case 0:
                 for (i = 0, lnb = res; i < obj->ioo_bufcnt; i++, lnb++) {
-                        /* flip_.. gets a ref, while free_page only frees
-                         * when it decrefs to 0 */
-                        if (rc == 0)
-                                flip_into_page_cache(inode, lnb->page);
-                        __free_page(lnb->page);
+                        filter_release_write_page(&obd->u.filter,
+                                                  res->dentry->d_inode, lnb,
+                                                  rc);
                 }
+
                 f_dput(res->dentry);
         }