Whamcloud - gitweb
smash the HEAD with the contents of b_cmd. HEAD_PRE_CMD_SMASH and
[fs/lustre-release.git] / lustre / obdfilter / filter_io_26.c
index cc0007f..5ce65c7 100644 (file)
 
 #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 {
         atomic_t numreqs;       /* number of reqs being processed */
         struct bio *bio_list;   /* list of completed bios */
         wait_queue_head_t wait;
-       int created[MAX_BLOCKS_PER_PAGE];
-       unsigned long blocks[MAX_BLOCKS_PER_PAGE];
+        int created[MAX_BLOCKS_PER_PAGE];
+        unsigned long blocks[MAX_BLOCKS_PER_PAGE];
         spinlock_t lock;
 };
 
@@ -68,18 +65,40 @@ static int dio_complete_routine(struct bio *bio, unsigned int done, int error)
 
 static int can_be_merged(struct bio *bio, sector_t sector)
 {
-       int size;
-       
-       if (!bio)
-               return 0;
-       
-       size = bio->bi_size >> 9;
-       return bio->bi_sector + size == sector ? 1 : 0;
+        int size;
+
+        if (!bio)
+                return 0;
+
+        size = bio->bi_size >> 9;
+        return bio->bi_sector + size == sector ? 1 : 0;
+}
+
+/* See if there are unallocated parts in given file region */
+static int filter_range_is_mapped(struct inode *inode, obd_size offset, int len)
+{
+        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)
+                          struct niobuf_local *res, struct obd_trans_info *oti,
+                          int rc)
 {
         struct obd_device *obd = exp->exp_obd;
         struct obd_run_ctxt saved;
@@ -87,9 +106,9 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
         struct fsfilt_objinfo fso;
         struct iattr iattr = { .ia_valid = ATTR_SIZE, .ia_size = 0, };
         struct inode *inode = NULL;
-        int rc = 0, i, k, cleanup_phase = 0, err;
+        int i, k, cleanup_phase = 0, err;
         unsigned long now = jiffies; /* DEBUGGING OST TIMEOUTS */
-       int blocks_per_page;
+        int blocks_per_page;
         struct dio_request *dreq;
         struct bio *bio = NULL;
         ENTRY;
@@ -97,9 +116,12 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
         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);
+        LASSERT(blocks_per_page <= MAX_BLOCKS_PER_PAGE);
 
         OBD_ALLOC(dreq, sizeof(*dreq));
         if (dreq == NULL)
@@ -114,9 +136,9 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
         fso.fso_bufcnt = obj->ioo_bufcnt;
 
         push_ctxt(&saved, &obd->obd_ctxt, NULL);
-        cleanup_phase = 2; 
+        cleanup_phase = 2;
 
-        oti->oti_handle = fsfilt_brw_start(obd, objcount, &fso, niocount, oti);
+        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,39 +150,48 @@ 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;
-               int offs;
+                sector_t sector;
+                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;
 
-               /* get block number for next page */
-                rc = ext3_map_inode_page(inode, lnb->page, dreq->blocks,
-                                                dreq->created, 1);
+                if (lnb->rc) /* ENOSPC, network RPC error */
+                        continue;
+
+                /* get block number for next page */
+                rc = fsfilt_map_inode_page(obd, inode, lnb->page, dreq->blocks,
+                                           dreq->created, 1);
                 if (rc)
                         GOTO(cleanup, rc);
 
-               for (k = 0; k < blocks_per_page; k++) {
-                       sector = dreq->blocks[k] * (inode->i_sb->s_blocksize >> 9);
-                       offs = k * inode->i_sb->s_blocksize;
+                for (k = 0; k < blocks_per_page; k++) {
+                        sector = dreq->blocks[k] *(inode->i_sb->s_blocksize>>9);
+                        offs = k * inode->i_sb->s_blocksize;
 
-                       if (!bio || !can_be_merged(bio, sector) ||
-                               !bio_add_page(bio, lnb->page, lnb->len, offs)) {
-                               if (bio) {
+                        if (!bio || !can_be_merged(bio, sector) ||
+                            !bio_add_page(bio, lnb->page, lnb->len, offs)) {
+                                if (bio) {
                                         atomic_inc(&dreq->numreqs);
-                                       submit_bio(WRITE, bio);
-                                       bio = NULL;
-                               }
-                               /* allocate new bio */
-                               bio = bio_alloc(GFP_NOIO, obj->ioo_bufcnt);
-                               bio->bi_bdev = inode->i_sb->s_bdev;
-                               bio->bi_sector = sector;
-                               bio->bi_end_io = dio_complete_routine; 
+                                        submit_bio(WRITE, bio);
+                                        bio = NULL;
+                                }
+                                /* allocate new bio */
+                                bio = bio_alloc(GFP_NOIO, obj->ioo_bufcnt);
+                                bio->bi_bdev = inode->i_sb->s_bdev;
+                                bio->bi_sector = sector;
+                                bio->bi_end_io = dio_complete_routine;
                                 bio->bi_private = dreq;
 
-                               if (!bio_add_page(bio, lnb->page, lnb->len, 0))
-                                       LBUG();
-                       }
-               }
+                                if (!bio_add_page(bio, lnb->page, lnb->len, 0))
+                                        LBUG();
+                        }
+                }
 
                 /* We expect these pages to be in offset order, but we'll
                  * be forgiving */
@@ -168,12 +199,14 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
                 if (this_size > iattr.ia_size)
                         iattr.ia_size = this_size;
         }
-       if (bio) {
+
+#warning This probably needs filemap_fdatasync() like filter_io_24 (bug 2366)
+        if (bio) {
                 atomic_inc(&dreq->numreqs);
                 submit_bio(WRITE, bio);
         }
 
-       /* time to wait for I/O completion */
+        /* time to wait for I/O completion */
         wait_event(dreq->wait, atomic_read(&dreq->numreqs) == 0);
 
         /* free all bios */
@@ -185,7 +218,6 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
 
         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);
@@ -208,6 +240,8 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa, int objcount,
                 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);