patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / fs / direct-io.c
index 0831f49..d498521 100644 (file)
@@ -690,8 +690,11 @@ out:
 static void clean_blockdev_aliases(struct dio *dio)
 {
        unsigned i;
+       unsigned nblocks;
 
-       for (i = 0; i < dio->blocks_available; i++) {
+       nblocks = dio->map_bh.b_size >> dio->inode->i_blkbits;
+
+       for (i = 0; i < nblocks; i++) {
                unmap_underlying_metadata(dio->map_bh.b_bdev,
                                        dio->map_bh.b_blocknr + i);
        }
@@ -987,13 +990,6 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
                }
        } /* end iovec loop */
 
-       if (ret == -ENOTBLK && rw == WRITE) {
-               /*
-                * The remaining part of the request will be
-                * be handled by buffered I/O when we return
-                */
-               ret = 0;
-       }
        /*
         * There may be some unwritten disk at the end of a part-written
         * fs-block-sized block.  Go zero that now.
@@ -1060,24 +1056,29 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
                        kfree(dio);
                }
        } else {
+               ssize_t transferred = 0;
+
                finished_one_bio(dio);
                ret2 = dio_await_completion(dio);
                if (ret == 0)
                        ret = ret2;
                if (ret == 0)
                        ret = dio->page_errors;
-               if (ret == 0 && dio->result) {
+               if (dio->result) {
                        loff_t i_size = i_size_read(inode);
 
-                       ret = dio->result;
+                       transferred = dio->result;
                        /*
                         * Adjust the return value if the read crossed a
                         * non-block-aligned EOF.
                         */
-                       if (rw == READ && (offset + ret > i_size))
-                               ret = i_size - offset;
+                       if (rw == READ && (offset + transferred > i_size))
+                               transferred = i_size - offset;
                }
-               dio_complete(dio, offset, ret);
+               dio_complete(dio, offset, transferred);
+               if (ret == 0)
+                       ret = transferred;
+
                /* We could have also come here on an AIO file extend */
                if (!is_sync_kiocb(iocb) && rw == WRITE &&
                    ret >= 0 && dio->result == dio->size)
@@ -1088,6 +1089,13 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
                        aio_complete(iocb, ret, 0);
                kfree(dio);
        }
+       if (ret == -ENOTBLK && rw == WRITE) {
+               /*
+                * The entire request will be be handled by buffered I/O
+                * when we return
+                */
+               ret = 0;
+       }
        return ret;
 }