Whamcloud - gitweb
LU-5393 osd-ldiskfs: read i_size once to protect against race
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_io.c
index 1e4e915..45822ff 100644 (file)
@@ -27,7 +27,7 @@
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2012, 2013, Intel Corporation.
+ * Copyright (c) 2012, 2014, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -147,9 +147,14 @@ void osd_fini_iobuf(struct osd_device *d, struct osd_iobuf *iobuf)
 
 static void dio_complete_routine(struct bio *bio, int error)
 {
-        struct osd_iobuf *iobuf = bio->bi_private;
-        struct bio_vec *bvl;
-        int i;
+       struct osd_iobuf *iobuf = bio->bi_private;
+#ifdef HAVE_BVEC_ITER
+       struct bvec_iter iter;
+       struct bio_vec bvl;
+#else
+       int iter;
+       struct bio_vec *bvl;
+#endif
 
         /* CAVEAT EMPTOR: possibly in IRQ context
          * DO NOT record procfs stats here!!! */
@@ -158,7 +163,7 @@ static void dio_complete_routine(struct bio *bio, int error)
                CERROR("***** bio->bi_private is NULL!  This should never "
                       "happen.  Normally, I would crash here, but instead I "
                       "will dump the bio contents to the console.  Please "
-                      "report this to <http://jira.whamcloud.com/> , along "
+                      "report this to <https://jira.hpdd.intel.com/> , along "
                       "with any interesting messages leading up to this point "
                       "(like SCSI errors, perhaps).  Because bi_private is "
                       "NULL, I can't wake up the thread that initiated this "
@@ -166,23 +171,23 @@ static void dio_complete_routine(struct bio *bio, int error)
                CERROR("bi_next: %p, bi_flags: %lx, bi_rw: %lu, bi_vcnt: %d, "
                       "bi_idx: %d, bi->size: %d, bi_end_io: %p, bi_cnt: %d, "
                       "bi_private: %p\n", bio->bi_next, bio->bi_flags,
-                      bio->bi_rw, bio->bi_vcnt, bio->bi_idx, bio->bi_size,
-                      bio->bi_end_io, atomic_read(&bio->bi_cnt),
-                      bio->bi_private);
+                       bio->bi_rw, bio->bi_vcnt, bio_idx(bio),
+                       bio_sectors(bio) << 9, bio->bi_end_io,
+                       atomic_read(&bio->bi_cnt), bio->bi_private);
                return;
        }
 
-        /* the check is outside of the cycle for performance reason -bzzz */
+       /* the check is outside of the cycle for performance reason -bzzz */
        if (!test_bit(__REQ_WRITE, &bio->bi_rw)) {
-                bio_for_each_segment(bvl, bio, i) {
-                        if (likely(error == 0))
-                                SetPageUptodate(bvl->bv_page);
-                        LASSERT(PageLocked(bvl->bv_page));
-                }
+               bio_for_each_segment(bvl, bio, iter) {
+                       if (likely(error == 0))
+                               SetPageUptodate(bvec_iter_page(&bvl, iter));
+                       LASSERT(PageLocked(bvec_iter_page(&bvl, iter)));
+               }
                atomic_dec(&iobuf->dr_dev->od_r_in_flight);
-        } else {
+       } else {
                atomic_dec(&iobuf->dr_dev->od_w_in_flight);
-        }
+       }
 
        /* any real error is good enough -bzzz */
        if (error != 0 && iobuf->dr_error == 0)
@@ -244,13 +249,10 @@ static void osd_submit_bio(int rw, struct bio *bio)
 
 static int can_be_merged(struct bio *bio, sector_t sector)
 {
-        unsigned int size;
-
-        if (!bio)
-                return 0;
+       if (bio == NULL)
+               return 0;
 
-        size = bio->bi_size >> 9;
-        return bio->bi_sector + size == sector ? 1 : 0;
+       return bio_end_sector(bio) == sector ? 1 : 0;
 }
 
 static int osd_do_bio(struct osd_device *osd, struct inode *inode,
@@ -316,23 +318,23 @@ static int osd_do_bio(struct osd_device *osd, struct inode *inode,
                                          blocksize * nblocks, page_offset) != 0)
                                 continue;       /* added this frag OK */
 
-                        if (bio != NULL) {
-                                struct request_queue *q =
-                                        bdev_get_queue(bio->bi_bdev);
-
-                                /* Dang! I have to fragment this I/O */
-                                CDEBUG(D_INODE, "bio++ sz %d vcnt %d(%d) "
-                                       "sectors %d(%d) psg %d(%d) hsg %d(%d)\n",
-                                       bio->bi_size,
-                                       bio->bi_vcnt, bio->bi_max_vecs,
-                                       bio->bi_size >> 9, queue_max_sectors(q),
+                       if (bio != NULL) {
+                               struct request_queue *q =
+                                       bdev_get_queue(bio->bi_bdev);
+                               unsigned int bi_size = bio_sectors(bio) << 9;
+
+                               /* Dang! I have to fragment this I/O */
+                               CDEBUG(D_INODE, "bio++ sz %d vcnt %d(%d) "
+                                      "sectors %d(%d) psg %d(%d) hsg %d(%d)\n",
+                                      bi_size, bio->bi_vcnt, bio->bi_max_vecs,
+                                      bio_sectors(bio),
+                                      queue_max_sectors(q),
                                        bio_phys_segments(q, bio),
                                        queue_max_phys_segments(q),
                                       0, queue_max_hw_segments(q));
-
-                                record_start_io(iobuf, bio->bi_size);
-                                osd_submit_bio(iobuf->dr_rw, bio);
-                        }
+                               record_start_io(iobuf, bi_size);
+                               osd_submit_bio(iobuf->dr_rw, bio);
+                       }
 
                        /* allocate new bio */
                        bio = bio_alloc(GFP_NOIO, min(BIO_MAX_PAGES,
@@ -346,23 +348,23 @@ static int osd_do_bio(struct osd_device *osd, struct inode *inode,
                                 goto out;
                         }
 
-                        bio->bi_bdev = inode->i_sb->s_bdev;
-                        bio->bi_sector = sector;
+                       bio->bi_bdev = inode->i_sb->s_bdev;
+                       bio_set_sector(bio, sector);
                        bio->bi_rw = (iobuf->dr_rw == 0) ? READ : WRITE;
-                        bio->bi_end_io = dio_complete_routine;
-                        bio->bi_private = iobuf;
+                       bio->bi_end_io = dio_complete_routine;
+                       bio->bi_private = iobuf;
 
-                        rc = bio_add_page(bio, page,
-                                          blocksize * nblocks, page_offset);
-                        LASSERT(rc != 0);
-                }
-        }
+                       rc = bio_add_page(bio, page,
+                                         blocksize * nblocks, page_offset);
+                       LASSERT(rc != 0);
+               }
+       }
 
-        if (bio != NULL) {
-                record_start_io(iobuf, bio->bi_size);
-                osd_submit_bio(iobuf->dr_rw, bio);
-                rc = 0;
-        }
+       if (bio != NULL) {
+               record_start_io(iobuf, bio_sectors(bio) << 9);
+               osd_submit_bio(iobuf->dr_rw, bio);
+               rc = 0;
+       }
 
 out:
        /* in order to achieve better IO throughput, we don't wait for writes
@@ -395,11 +397,11 @@ static int osd_map_remote_to_local(loff_t offset, ssize_t len, int *nrpages,
                         plen = len;
                lnb->lnb_file_offset = offset;
                lnb->lnb_page_offset = poff;
-                lnb->len = plen;
-                /* lb->flags = rnb->flags; */
-                lnb->flags = 0;
-                lnb->page = NULL;
-                lnb->rc = 0;
+               lnb->lnb_len = plen;
+               /* lnb->lnb_flags = rnb->rnb_flags; */
+               lnb->lnb_flags = 0;
+               lnb->lnb_page = NULL;
+               lnb->lnb_rc = 0;
 
                 LASSERTF(plen <= len, "plen %u, len %lld\n", plen,
                          (long long) len);
@@ -412,7 +414,7 @@ static int osd_map_remote_to_local(loff_t offset, ssize_t len, int *nrpages,
         RETURN(0);
 }
 
-struct page *osd_get_page(struct dt_object *dt, loff_t offset, int rw)
+static struct page *osd_get_page(struct dt_object *dt, loff_t offset, int rw)
 {
         struct inode      *inode = osd_dt_obj(dt)->oo_inode;
         struct osd_device *d = osd_obj2dev(osd_dt_obj(dt));
@@ -433,71 +435,106 @@ struct page *osd_get_page(struct dt_object *dt, loff_t offset, int rw)
  * journal_start
  * i_mutex
  * page lock
-
- * osd write path
   * lock page(s)
   * journal_start
   * truncate_sem
-
+ *
+ * osd write path:
*  - lock page(s)
*  - journal_start
*  - truncate_sem
+ *
  * ext4 vmtruncate:
-    * lock pages, unlock
-    * journal_start
-    * lock partial page
-    * i_data_sem
-
-*/
-int osd_bufs_get(const struct lu_env *env, struct dt_object *d, loff_t pos,
-                 ssize_t len, struct niobuf_local *lnb, int rw,
-                 struct lustre_capa *capa)
+ *  - lock pages, unlock
+ *  - journal_start
+ *  - lock partial page
+ *  - i_data_sem
+ *
+ */
+
+/**
+ * Unlock and release pages loaded by osd_bufs_get()
+ *
+ * Unlock \a npages pages from \a lnb and drop the refcount on them.
+ *
+ * \param env          thread execution environment
+ * \param dt           dt object undergoing IO (OSD object + methods)
+ * \param lnb          array of pages undergoing IO
+ * \param npages       number of pages in \a lnb
+ *
+ * \retval 0           always
+ */
+static int osd_bufs_put(const struct lu_env *env, struct dt_object *dt,
+                       struct niobuf_local *lnb, int npages)
 {
-        struct osd_object   *obj    = osd_dt_obj(d);
-        int npages, i, rc = 0;
-
-        LASSERT(obj->oo_inode);
-
-        osd_map_remote_to_local(pos, len, &npages, lnb);
-
-        for (i = 0; i < npages; i++, lnb++) {
-               lnb->page = osd_get_page(d, lnb->lnb_file_offset, rw);
-                if (lnb->page == NULL)
-                        GOTO(cleanup, rc = -ENOMEM);
-
-                /* DLM locking protects us from write and truncate competing
-                 * for same region, but truncate can leave dirty page in the
-                 * cache. it's possible the writeout on a such a page is in
-                 * progress when we access it. it's also possible that during
-                 * this writeout we put new (partial) data, but then won't
-                 * be able to proceed in filter_commitrw_write(). thus let's
-                 * just wait for writeout completion, should be rare enough.
-                 * -bzzz */
-                wait_on_page_writeback(lnb->page);
-                BUG_ON(PageWriteback(lnb->page));
-
-                lu_object_get(&d->do_lu);
-        }
-        rc = i;
+       int i;
 
-cleanup:
-        RETURN(rc);
+       for (i = 0; i < npages; i++) {
+               if (lnb[i].lnb_page == NULL)
+                       continue;
+               LASSERT(PageLocked(lnb[i].lnb_page));
+               unlock_page(lnb[i].lnb_page);
+               page_cache_release(lnb[i].lnb_page);
+               lu_object_put(env, &dt->do_lu);
+               lnb[i].lnb_page = NULL;
+       }
+
+       RETURN(0);
 }
 
-static int osd_bufs_put(const struct lu_env *env, struct dt_object *dt,
-                        struct niobuf_local *lnb, int npages)
+/**
+ * Load and lock pages undergoing IO
+ *
+ * Pages as described in the \a lnb array are fetched (from disk or cache)
+ * and locked for IO by the caller.
+ *
+ * DLM locking protects us from write and truncate competing for same region,
+ * but partial-page truncate can leave dirty pages in the cache for ldiskfs.
+ * It's possible the writeout on a such a page is in progress when we access
+ * it. It's also possible that during this writeout we put new (partial) data
+ * into the page, but won't be able to proceed in filter_commitrw_write().
+ * Therefore, just wait for writeout completion as it should be rare enough.
+ *
+ * \param env          thread execution environment
+ * \param dt           dt object undergoing IO (OSD object + methods)
+ * \param pos          byte offset of IO start
+ * \param len          number of bytes of IO
+ * \param lnb          array of extents undergoing IO
+ * \param rw           read or write operation?
+ * \param capa         capabilities
+ *
+ * \retval pages       (zero or more) loaded successfully
+ * \retval -ENOMEM     on memory/page allocation error
+ */
+static int osd_bufs_get(const struct lu_env *env, struct dt_object *dt,
+                       loff_t pos, ssize_t len, struct niobuf_local *lnb,
+                       int rw, struct lustre_capa *capa)
 {
-        int                     i;
+       struct osd_object   *obj    = osd_dt_obj(dt);
+       int npages, i, rc = 0;
 
-        for (i = 0; i < npages; i++) {
-                if (lnb[i].page == NULL)
-                        continue;
-                LASSERT(PageLocked(lnb[i].page));
-                unlock_page(lnb[i].page);
-                page_cache_release(lnb[i].page);
-                lu_object_put(env, &dt->do_lu);
-                lnb[i].page = NULL;
-        }
-        RETURN(0);
+       LASSERT(obj->oo_inode);
+
+       osd_map_remote_to_local(pos, len, &npages, lnb);
+
+       for (i = 0; i < npages; i++, lnb++) {
+               lnb->lnb_page = osd_get_page(dt, lnb->lnb_file_offset, rw);
+               if (lnb->lnb_page == NULL)
+                       GOTO(cleanup, rc = -ENOMEM);
+
+               wait_on_page_writeback(lnb->lnb_page);
+               BUG_ON(PageWriteback(lnb->lnb_page));
+
+               lu_object_get(&dt->do_lu);
+       }
+
+       RETURN(i);
+
+cleanup:
+       if (i > 0)
+               osd_bufs_put(env, dt, lnb - i, i);
+       return rc;
 }
 
+#ifndef HAVE_LDISKFS_MAP_BLOCKS
+
 #ifdef HAVE_EXT_PBLOCK /* Name changed to ext4_ext_pblock for kernel 2.6.35 */
 #define ldiskfs_ext_pblock(ex) ext_pblock((ex))
 #endif
@@ -617,7 +654,8 @@ static int ldiskfs_ext_new_extent_cb(struct inode *inode,
        tgen = LDISKFS_I(inode)->i_ext_generation;
        count = ldiskfs_ext_calc_credits_for_insert(inode, path);
 
-       handle = ldiskfs_journal_start(inode, count + LDISKFS_ALLOC_NEEDED + 1);
+       handle = osd_journal_start(inode, LDISKFS_HT_MISC,
+                                  count + LDISKFS_ALLOC_NEEDED + 1);
        if (IS_ERR(handle)) {
                return PTR_ERR(handle);
        }
@@ -725,9 +763,9 @@ map:
        return err;
 }
 
-int osd_ldiskfs_map_nblocks(struct inode *inode, unsigned long block,
-                           unsigned long num, unsigned long *blocks,
-                           int create)
+static int osd_ldiskfs_map_nblocks(struct inode *inode, unsigned long block,
+                                  unsigned long num, unsigned long *blocks,
+                                  int create)
 {
        struct bpointers bp;
        int err;
@@ -747,14 +785,45 @@ int osd_ldiskfs_map_nblocks(struct inode *inode, unsigned long block,
        return err;
 }
 
-int osd_ldiskfs_map_ext_inode_pages(struct inode *inode, struct page **page,
-                                   int pages, unsigned long *blocks,
-                                   int create)
+static int osd_ldiskfs_map_bm_inode_pages(struct inode *inode,
+                                         struct page **page, int pages,
+                                         unsigned long *blocks, int create)
+{
+       int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
+       pgoff_t bitmap_max_page_index;
+       unsigned long *b;
+       int rc = 0, i;
+
+       bitmap_max_page_index = LDISKFS_SB(inode->i_sb)->s_bitmap_maxbytes >>
+                               PAGE_SHIFT;
+       for (i = 0, b = blocks; i < pages; i++, page++) {
+               if ((*page)->index + 1 >= bitmap_max_page_index) {
+                       rc = -EFBIG;
+                       break;
+               }
+               rc = ldiskfs_map_inode_page(inode, *page, b, create);
+               if (rc) {
+                       CERROR("ino %lu, blk %lu create %d: rc %d\n",
+                              inode->i_ino, *b, create, rc);
+                       break;
+               }
+               b += blocks_per_page;
+       }
+       return rc;
+}
+
+static int osd_ldiskfs_map_ext_inode_pages(struct inode *inode,
+                                          struct page **page,
+                                          int pages, unsigned long *blocks,
+                                          int create)
 {
        int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
        int rc = 0, i = 0;
        struct page *fp = NULL;
        int clen = 0;
+       pgoff_t extent_max_page_index;
+
+       extent_max_page_index = inode->i_sb->s_maxbytes >> PAGE_SHIFT;
 
        CDEBUG(D_OTHER, "inode %lu: map %d pages from %lu\n",
                inode->i_ino, pages, (*page)->index);
@@ -776,6 +845,9 @@ int osd_ldiskfs_map_ext_inode_pages(struct inode *inode, struct page **page,
                        continue;
                }
 
+               if (fp->index + i >= extent_max_page_index)
+                       GOTO(cleanup, rc = -EFBIG);
+
                /* process found extent */
                rc = osd_ldiskfs_map_nblocks(inode, fp->index * blocks_per_page,
                                             clen * blocks_per_page, blocks,
@@ -796,30 +868,9 @@ cleanup:
        return rc;
 }
 
-int osd_ldiskfs_map_bm_inode_pages(struct inode *inode, struct page **page,
-                                  int pages, unsigned long *blocks,
-                                  int create)
-{
-       int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
-       unsigned long *b;
-       int rc = 0, i;
-
-       for (i = 0, b = blocks; i < pages; i++, page++) {
-               rc = ldiskfs_map_inode_page(inode, *page, b, create);
-               if (rc) {
-                       CERROR("ino %lu, blk %lu create %d: rc %d\n",
-                              inode->i_ino, *b, create, rc);
-                       break;
-               }
-
-               b += blocks_per_page;
-       }
-       return rc;
-}
-
 static int osd_ldiskfs_map_inode_pages(struct inode *inode, struct page **page,
                                       int pages, unsigned long *blocks,
-                                      int create, struct mutex *optional_mutex)
+                                      int create)
 {
        int rc;
 
@@ -828,14 +879,94 @@ static int osd_ldiskfs_map_inode_pages(struct inode *inode, struct page **page,
                                                     blocks, create);
                return rc;
        }
-       if (optional_mutex != NULL)
-               mutex_lock(optional_mutex);
        rc = osd_ldiskfs_map_bm_inode_pages(inode, page, pages, blocks, create);
-       if (optional_mutex != NULL)
-               mutex_unlock(optional_mutex);
 
        return rc;
 }
+#else
+static int osd_ldiskfs_map_inode_pages(struct inode *inode, struct page **page,
+                                      int pages, unsigned long *blocks,
+                                      int create)
+{
+       int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits;
+       int rc = 0, i = 0;
+       struct page *fp = NULL;
+       int clen = 0;
+       pgoff_t max_page_index;
+
+       max_page_index = inode->i_sb->s_maxbytes >> PAGE_SHIFT;
+
+       CDEBUG(D_OTHER, "inode %lu: map %d pages from %lu\n",
+               inode->i_ino, pages, (*page)->index);
+
+       /* pages are sorted already. so, we just have to find
+        * contig. space and process them properly */
+       while (i < pages) {
+               long blen, total = 0;
+               handle_t *handle = NULL;
+               struct ldiskfs_map_blocks map = { 0 };
+
+               if (fp == NULL) { /* start new extent */
+                       fp = *page++;
+                       clen = 1;
+                       if (++i != pages)
+                               continue;
+               } else if (fp->index + clen == (*page)->index) {
+                       /* continue the extent */
+                       page++;
+                       clen++;
+                       if (++i != pages)
+                               continue;
+               }
+               if (fp->index + i >= max_page_index)
+                       GOTO(cleanup, rc = -EFBIG);
+               /* process found extent */
+               map.m_lblk = fp->index * blocks_per_page;
+               map.m_len = blen = clen * blocks_per_page;
+               if (create) {
+                       create = LDISKFS_GET_BLOCKS_CREATE;
+                       handle = ldiskfs_journal_current_handle();
+                       LASSERT(handle != NULL);
+               }
+cont_map:
+               rc = ldiskfs_map_blocks(handle, inode, &map, create);
+               if (rc >= 0) {
+                       int c = 0;
+                       for (; total < blen && c < map.m_len; c++, total++) {
+                               if (rc == 0) {
+                                       *(blocks + total) = 0;
+                                       total++;
+                                       break;
+                               } else {
+                                       *(blocks + total) = map.m_pblk + c;
+                                       /* unmap any possible underlying
+                                        * metadata from the block device
+                                        * mapping.  bug 6998. */
+                                       if ((map.m_flags & LDISKFS_MAP_NEW) &&
+                                           create)
+                                               unmap_underlying_metadata(
+                                                       inode->i_sb->s_bdev,
+                                                       map.m_pblk + c);
+                               }
+                       }
+                       rc = 0;
+               }
+               if (rc == 0 && total < blen) {
+                       map.m_lblk = fp->index * blocks_per_page + total;
+                       map.m_len = blen - total;
+                       goto cont_map;
+               }
+               if (rc != 0)
+                       GOTO(cleanup, rc);
+
+               /* look for next extent */
+               fp = NULL;
+               blocks += blocks_per_page * clen;
+       }
+cleanup:
+       return rc;
+}
+#endif /* HAVE_LDISKFS_MAP_BLOCKS */
 
 static int osd_write_prep(const struct lu_env *env, struct dt_object *dt,
                           struct niobuf_local *lnb, int npages)
@@ -870,34 +1001,34 @@ static int osd_write_prep(const struct lu_env *env, struct dt_object *dt,
        do_gettimeofday(&start);
        for (i = 0; i < npages; i++) {
 
-                if (cache == 0)
-                        generic_error_remove_page(inode->i_mapping,
-                                                  lnb[i].page);
+               if (cache == 0)
+                       generic_error_remove_page(inode->i_mapping,
+                                                 lnb[i].lnb_page);
 
-                /*
-                 * till commit the content of the page is undefined
-                 * we'll set it uptodate once bulk is done. otherwise
-                 * subsequent reads can access non-stable data
-                 */
-                ClearPageUptodate(lnb[i].page);
+               /*
+                * till commit the content of the page is undefined
+                * we'll set it uptodate once bulk is done. otherwise
+                * subsequent reads can access non-stable data
+                */
+               ClearPageUptodate(lnb[i].lnb_page);
 
-               if (lnb[i].len == PAGE_CACHE_SIZE)
-                        continue;
+               if (lnb[i].lnb_len == PAGE_CACHE_SIZE)
+                       continue;
 
-                if (maxidx >= lnb[i].page->index) {
-                        osd_iobuf_add_page(iobuf, lnb[i].page);
-                } else {
-                        long off;
-                        char *p = kmap(lnb[i].page);
+               if (maxidx >= lnb[i].lnb_page->index) {
+                       osd_iobuf_add_page(iobuf, lnb[i].lnb_page);
+               } else {
+                       long off;
+                       char *p = kmap(lnb[i].lnb_page);
 
                        off = lnb[i].lnb_page_offset;
                        if (off)
                                memset(p, 0, off);
-                       off = (lnb[i].lnb_page_offset + lnb[i].len) &
+                       off = (lnb[i].lnb_page_offset + lnb[i].lnb_len) &
                              ~CFS_PAGE_MASK;
-                        if (off)
+                       if (off)
                                memset(p + off, 0, PAGE_CACHE_SIZE - off);
-                        kunmap(lnb[i].page);
+                       kunmap(lnb[i].lnb_page);
                }
        }
        do_gettimeofday(&end);
@@ -907,8 +1038,7 @@ static int osd_write_prep(const struct lu_env *env, struct dt_object *dt,
         if (iobuf->dr_npages) {
                rc = osd_ldiskfs_map_inode_pages(inode, iobuf->dr_pages,
                                                 iobuf->dr_npages,
-                                                iobuf->dr_blocks,
-                                                0, NULL);
+                                                iobuf->dr_blocks, 0);
                 if (likely(rc == 0)) {
                         rc = osd_do_bio(osd, inode, iobuf);
                         /* do IO stats for preparation reads */
@@ -919,7 +1049,7 @@ static int osd_write_prep(const struct lu_env *env, struct dt_object *dt,
 }
 
 /* Check if a block is allocated or not */
-static int osd_is_mapped(struct inode *inode, obd_size offset)
+static int osd_is_mapped(struct inode *inode, u64 offset)
 {
        sector_t (*fs_bmap)(struct address_space *, sector_t);
 
@@ -970,7 +1100,7 @@ static int osd_declare_write_commit(const struct lu_env *env,
         /* calculate number of extents (probably better to pass nb) */
        for (i = 0; i < npages; i++) {
                if (i && lnb[i].lnb_file_offset !=
-                   lnb[i - 1].lnb_file_offset + lnb[i - 1].len)
+                   lnb[i - 1].lnb_file_offset + lnb[i - 1].lnb_len)
                        extents++;
 
                if (!osd_is_mapped(inode, lnb[i].lnb_file_offset))
@@ -985,8 +1115,8 @@ static int osd_declare_write_commit(const struct lu_env *env,
                 *
                 * XXX we could handle this on per-lnb basis as done by
                 * grant. */
-               if ((lnb[i].flags & OBD_BRW_NOQUOTA) ||
-                   (lnb[i].flags & (OBD_BRW_FROM_GRANT | OBD_BRW_SYNC)) ==
+               if ((lnb[i].lnb_flags & OBD_BRW_NOQUOTA) ||
+                   (lnb[i].lnb_flags & (OBD_BRW_FROM_GRANT | OBD_BRW_SYNC)) ==
                    OBD_BRW_FROM_GRANT)
                        ignore_quota = true;
        }
@@ -1034,19 +1164,19 @@ static int osd_declare_write_commit(const struct lu_env *env,
                 oh->ot_credits += newblocks;
 
        /* make sure the over quota flags were not set */
-       lnb[0].flags &= ~(OBD_BRW_OVER_USRQUOTA | OBD_BRW_OVER_GRPQUOTA);
+       lnb[0].lnb_flags &= ~(OBD_BRW_OVER_USRQUOTA | OBD_BRW_OVER_GRPQUOTA);
 
-       rc = osd_declare_inode_qid(env, inode->i_uid, inode->i_gid,
-                                  quota_space, oh, true, true, &flags,
-                                  ignore_quota);
+       rc = osd_declare_inode_qid(env, i_uid_read(inode), i_gid_read(inode),
+                                  quota_space, oh, osd_dt_obj(dt), true,
+                                  &flags, ignore_quota);
 
        /* we need only to store the overquota flags in the first lnb for
         * now, once we support multiple objects BRW, this code needs be
         * revised. */
        if (flags & QUOTA_FL_OVER_USRQUOTA)
-               lnb[0].flags |= OBD_BRW_OVER_USRQUOTA;
+               lnb[0].lnb_flags |= OBD_BRW_OVER_USRQUOTA;
        if (flags & QUOTA_FL_OVER_GRPQUOTA)
-               lnb[0].flags |= OBD_BRW_OVER_GRPQUOTA;
+               lnb[0].lnb_flags |= OBD_BRW_OVER_GRPQUOTA;
 
        RETURN(rc);
 }
@@ -1073,37 +1203,38 @@ static int osd_write_commit(const struct lu_env *env, struct dt_object *dt,
        ll_vfs_dq_init(inode);
 
         for (i = 0; i < npages; i++) {
-                if (lnb[i].rc == -ENOSPC &&
+               if (lnb[i].lnb_rc == -ENOSPC &&
                    osd_is_mapped(inode, lnb[i].lnb_file_offset)) {
-                        /* Allow the write to proceed if overwriting an
-                         * existing block */
-                        lnb[i].rc = 0;
-                }
+                       /* Allow the write to proceed if overwriting an
+                        * existing block */
+                       lnb[i].lnb_rc = 0;
+               }
 
-                if (lnb[i].rc) { /* ENOSPC, network RPC error, etc. */
-                        CDEBUG(D_INODE, "Skipping [%d] == %d\n", i,
-                               lnb[i].rc);
-                        LASSERT(lnb[i].page);
-                        generic_error_remove_page(inode->i_mapping,lnb[i].page);
-                        continue;
-                }
+               if (lnb[i].lnb_rc) { /* ENOSPC, network RPC error, etc. */
+                       CDEBUG(D_INODE, "Skipping [%d] == %d\n", i,
+                              lnb[i].lnb_rc);
+                       LASSERT(lnb[i].lnb_page);
+                       generic_error_remove_page(inode->i_mapping,
+                                                 lnb[i].lnb_page);
+                       continue;
+               }
 
-                LASSERT(PageLocked(lnb[i].page));
-                LASSERT(!PageWriteback(lnb[i].page));
+               LASSERT(PageLocked(lnb[i].lnb_page));
+               LASSERT(!PageWriteback(lnb[i].lnb_page));
 
-               if (lnb[i].lnb_file_offset + lnb[i].len > isize)
-                       isize = lnb[i].lnb_file_offset + lnb[i].len;
+               if (lnb[i].lnb_file_offset + lnb[i].lnb_len > isize)
+                       isize = lnb[i].lnb_file_offset + lnb[i].lnb_len;
 
-                /*
-                 * Since write and truncate are serialized by oo_sem, even
-                 * partial-page truncate should not leave dirty pages in the
-                 * page cache.
-                 */
-                LASSERT(!PageDirty(lnb[i].page));
+               /*
+                * Since write and truncate are serialized by oo_sem, even
+                * partial-page truncate should not leave dirty pages in the
+                * page cache.
+                */
+               LASSERT(!PageDirty(lnb[i].lnb_page));
 
-                SetPageUptodate(lnb[i].page);
+               SetPageUptodate(lnb[i].lnb_page);
 
-                osd_iobuf_add_page(iobuf, lnb[i].page);
+               osd_iobuf_add_page(iobuf, lnb[i].lnb_page);
         }
 
         if (OBD_FAIL_CHECK(OBD_FAIL_OST_MAPBLK_ENOSPC)) {
@@ -1111,8 +1242,7 @@ static int osd_write_commit(const struct lu_env *env, struct dt_object *dt,
         } else if (iobuf->dr_npages > 0) {
                rc = osd_ldiskfs_map_inode_pages(inode, iobuf->dr_pages,
                                                 iobuf->dr_npages,
-                                                iobuf->dr_blocks,
-                                                1, NULL);
+                                                iobuf->dr_blocks, 1);
         } else {
                 /* no pages to write, no transno is needed */
                 thandle->th_local = 1;
@@ -1135,14 +1265,15 @@ static int osd_write_commit(const struct lu_env *env, struct dt_object *dt,
         if (unlikely(rc != 0)) {
                 /* if write fails, we should drop pages from the cache */
                 for (i = 0; i < npages; i++) {
-                        if (lnb[i].page == NULL)
-                                continue;
-                        LASSERT(PageLocked(lnb[i].page));
-                        generic_error_remove_page(inode->i_mapping,lnb[i].page);
-                }
-        }
+                       if (lnb[i].lnb_page == NULL)
+                               continue;
+                       LASSERT(PageLocked(lnb[i].lnb_page));
+                       generic_error_remove_page(inode->i_mapping,
+                                                 lnb[i].lnb_page);
+               }
+       }
 
-        RETURN(rc);
+       RETURN(rc);
 }
 
 static int osd_read_prep(const struct lu_env *env, struct dt_object *dt,
@@ -1154,7 +1285,8 @@ static int osd_read_prep(const struct lu_env *env, struct dt_object *dt,
         struct osd_device *osd = osd_obj2dev(osd_dt_obj(dt));
         struct timeval start, end;
         unsigned long timediff;
-        int rc = 0, i, m = 0, cache = 0;
+       int rc = 0, i, cache = 0, cache_hits = 0, cache_misses = 0;
+       loff_t isize;
 
         LASSERT(inode);
 
@@ -1162,47 +1294,55 @@ static int osd_read_prep(const struct lu_env *env, struct dt_object *dt,
        if (unlikely(rc != 0))
                RETURN(rc);
 
+       isize = i_size_read(inode);
+
        if (osd->od_read_cache)
                cache = 1;
-       if (i_size_read(inode) > osd->od_readcache_max_filesize)
+       if (isize > osd->od_readcache_max_filesize)
                cache = 0;
 
        do_gettimeofday(&start);
        for (i = 0; i < npages; i++) {
 
-               if (i_size_read(inode) <= lnb[i].lnb_file_offset)
-                        /* If there's no more data, abort early.
-                         * lnb->rc == 0, so it's easy to detect later. */
-                        break;
+               if (isize <= lnb[i].lnb_file_offset)
+                       /* If there's no more data, abort early.
+                        * lnb->lnb_rc == 0, so it's easy to detect later. */
+                       break;
+
+               if (isize < lnb[i].lnb_file_offset + lnb[i].lnb_len - 1)
+                       lnb[i].lnb_rc = isize - lnb[i].lnb_file_offset;
+               else
+                       lnb[i].lnb_rc = lnb[i].lnb_len;
+
+               if (PageUptodate(lnb[i].lnb_page)) {
+                       cache_hits++;
+               } else {
+                       cache_misses++;
+                       osd_iobuf_add_page(iobuf, lnb[i].lnb_page);
+               }
 
-                if (i_size_read(inode) <
-                   lnb[i].lnb_file_offset + lnb[i].len - 1)
-                       lnb[i].rc = i_size_read(inode) - lnb[i].lnb_file_offset;
-                else
-                        lnb[i].rc = lnb[i].len;
-                m += lnb[i].len;
-
-                lprocfs_counter_add(osd->od_stats, LPROC_OSD_CACHE_ACCESS, 1);
-                if (PageUptodate(lnb[i].page)) {
-                        lprocfs_counter_add(osd->od_stats,
-                                            LPROC_OSD_CACHE_HIT, 1);
-                } else {
-                        lprocfs_counter_add(osd->od_stats,
-                                            LPROC_OSD_CACHE_MISS, 1);
-                        osd_iobuf_add_page(iobuf, lnb[i].page);
-                }
                if (cache == 0)
-                       generic_error_remove_page(inode->i_mapping,lnb[i].page);
+                       generic_error_remove_page(inode->i_mapping,
+                                                 lnb[i].lnb_page);
        }
        do_gettimeofday(&end);
        timediff = cfs_timeval_sub(&end, &start, NULL);
        lprocfs_counter_add(osd->od_stats, LPROC_OSD_GET_PAGE, timediff);
 
+       if (cache_hits != 0)
+               lprocfs_counter_add(osd->od_stats, LPROC_OSD_CACHE_HIT,
+                                   cache_hits);
+       if (cache_misses != 0)
+               lprocfs_counter_add(osd->od_stats, LPROC_OSD_CACHE_MISS,
+                                   cache_misses);
+       if (cache_hits + cache_misses != 0)
+               lprocfs_counter_add(osd->od_stats, LPROC_OSD_CACHE_ACCESS,
+                                   cache_hits + cache_misses);
+
         if (iobuf->dr_npages) {
                rc = osd_ldiskfs_map_inode_pages(inode, iobuf->dr_pages,
                                                 iobuf->dr_npages,
-                                                iobuf->dr_blocks,
-                                                0, NULL);
+                                                iobuf->dr_blocks, 0);
                 rc = osd_do_bio(osd, inode, iobuf);
 
                 /* IO stats will be done in osd_bufs_put() */
@@ -1266,15 +1406,21 @@ int osd_ldiskfs_read(struct inode *inode, void *buf, int size, loff_t *offs)
                 boffs = *offs & (blocksize - 1);
                 csize = min(blocksize - boffs, size);
                 bh = ldiskfs_bread(NULL, inode, block, 0, &err);
-                if (!bh) {
-                        CERROR("%s: can't read %u@%llu on ino %lu: rc = %d\n",
-                               LDISKFS_SB(inode->i_sb)->s_es->s_volume_name,
-                               csize, *offs, inode->i_ino, err);
-                        return err;
-                }
+               if (err != 0) {
+                       CERROR("%s: can't read %u@%llu on ino %lu: rc = %d\n",
+                              LDISKFS_SB(inode->i_sb)->s_es->s_volume_name,
+                              csize, *offs, inode->i_ino, err);
+                       if (bh != NULL)
+                               brelse(bh);
+                       return err;
+               }
 
-                memcpy(buf, bh->b_data + boffs, csize);
-                brelse(bh);
+               if (bh != NULL) {
+                       memcpy(buf, bh->b_data + boffs, csize);
+                       brelse(bh);
+               } else {
+                       memset(buf, 0, csize);
+               }
 
                 *offs += csize;
                 buf += csize;
@@ -1446,8 +1592,9 @@ out:
         * as llog or last_rcvd files. We needn't enforce quota on those
         * objects, so always set the lqi_space as 0. */
        if (inode != NULL)
-               rc = osd_declare_inode_qid(env, inode->i_uid, inode->i_gid,
-                                          0, oh, true, true, NULL, false);
+               rc = osd_declare_inode_qid(env, i_uid_read(inode),
+                                          i_gid_read(inode), 0, oh, obj, true,
+                                          NULL, false);
        RETURN(rc);
 }
 
@@ -1507,11 +1654,11 @@ int osd_ldiskfs_write_record(struct inode *inode, void *buf, int bufsize,
                                err);
                         break;
                 }
-                LASSERTF(boffs + size <= bh->b_size,
-                         "boffs %d size %d bh->b_size %lu",
-                         boffs, size, (unsigned long)bh->b_size);
+               LASSERTF(boffs + size <= bh->b_size,
+                        "boffs %d size %d bh->b_size %lu\n",
+                        boffs, size, (unsigned long)bh->b_size);
                 memcpy(bh->b_data + boffs, buf, size);
-                err = ldiskfs_journal_dirty_metadata(handle, bh);
+               err = ldiskfs_handle_dirty_metadata(handle, NULL, bh);
                 if (err)
                         break;
 
@@ -1611,8 +1758,8 @@ static int osd_declare_punch(const struct lu_env *env, struct dt_object *dt,
        inode = osd_dt_obj(dt)->oo_inode;
        LASSERT(inode);
 
-       rc = osd_declare_inode_qid(env, inode->i_uid, inode->i_gid, 0, oh,
-                                  true, true, NULL, false);
+       rc = osd_declare_inode_qid(env, i_uid_read(inode), i_gid_read(inode),
+                                  0, oh, osd_dt_obj(dt), true, NULL, false);
        RETURN(rc);
 }