]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/ocfs2/aops.c
[PATCH] mark address_space_operations const
[mirror_ubuntu-bionic-kernel.git] / fs / ocfs2 / aops.c
index bf931ba1d36478e323f3e1c4ebc54be12ea335fb..cca71317b6d6144e5bd381bacb9149a6f9fddde5 100644 (file)
@@ -276,13 +276,29 @@ static int ocfs2_writepage(struct page *page, struct writeback_control *wbc)
        return ret;
 }
 
+/* This can also be called from ocfs2_write_zero_page() which has done
+ * it's own cluster locking. */
+int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
+                              unsigned from, unsigned to)
+{
+       int ret;
+
+       down_read(&OCFS2_I(inode)->ip_alloc_sem);
+
+       ret = block_prepare_write(page, from, to, ocfs2_get_block);
+
+       up_read(&OCFS2_I(inode)->ip_alloc_sem);
+
+       return ret;
+}
+
 /*
  * ocfs2_prepare_write() can be an outer-most ocfs2 call when it is called
  * from loopback.  It must be able to perform its own locking around
  * ocfs2_get_block().
  */
-int ocfs2_prepare_write(struct file *file, struct page *page,
-                       unsigned from, unsigned to)
+static int ocfs2_prepare_write(struct file *file, struct page *page,
+                              unsigned from, unsigned to)
 {
        struct inode *inode = page->mapping->host;
        int ret;
@@ -295,11 +311,7 @@ int ocfs2_prepare_write(struct file *file, struct page *page,
                goto out;
        }
 
-       down_read(&OCFS2_I(inode)->ip_alloc_sem);
-
-       ret = block_prepare_write(page, from, to, ocfs2_get_block);
-
-       up_read(&OCFS2_I(inode)->ip_alloc_sem);
+       ret = ocfs2_prepare_write_nolock(inode, page, from, to);
 
        ocfs2_meta_unlock(inode, 0);
 out:
@@ -540,7 +552,6 @@ bail:
  *                                     fs_count, map_bh, dio->rw == WRITE);
  */
 static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
-                                    unsigned long max_blocks,
                                     struct buffer_head *bh_result, int create)
 {
        int ret;
@@ -548,6 +559,7 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
        u64 p_blkno;
        int contig_blocks;
        unsigned char blocksize_bits;
+       unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
 
        if (!inode || !bh_result) {
                mlog(ML_ERROR, "inode or bh_result is null\n");
@@ -625,16 +637,36 @@ static ssize_t ocfs2_direct_IO(int rw,
        int ret;
 
        mlog_entry_void();
+
+       /*
+        * We get PR data locks even for O_DIRECT.  This allows
+        * concurrent O_DIRECT I/O but doesn't let O_DIRECT with
+        * extending and buffered zeroing writes race.  If they did
+        * race then the buffered zeroing could be written back after
+        * the O_DIRECT I/O.  It's one thing to tell people not to mix
+        * buffered and O_DIRECT writes, but expecting them to
+        * understand that file extension is also an implicit buffered
+        * write is too much.  By getting the PR we force writeback of
+        * the buffered zeroing before proceeding.
+        */
+       ret = ocfs2_data_lock(inode, 0);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+       ocfs2_data_unlock(inode, 0);
+
        ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
                                            inode->i_sb->s_bdev, iov, offset,
                                            nr_segs, 
                                            ocfs2_direct_IO_get_blocks,
                                            ocfs2_dio_end_io);
+out:
        mlog_exit(ret);
        return ret;
 }
 
-struct address_space_operations ocfs2_aops = {
+const struct address_space_operations ocfs2_aops = {
        .readpage       = ocfs2_readpage,
        .writepage      = ocfs2_writepage,
        .prepare_write  = ocfs2_prepare_write,