udf: Convert in-ICB files to use udf_write_begin()
authorJan Kara <jack@suse.cz>
Tue, 24 Jan 2023 11:07:37 +0000 (12:07 +0100)
committerJan Kara <jack@suse.cz>
Thu, 26 Jan 2023 15:46:35 +0000 (16:46 +0100)
Switching address_space_operations while a file is used is difficult to
do in a race-free way. To be able to use single address_space_operations
in UDF, make in-ICB files use udf_write_begin().

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jan Kara <jack@suse.cz>
fs/udf/file.c
fs/udf/inode.c
fs/udf/udfdecl.h

index 6bab6aa7770aab210dc186ab758d5557e8570d72..16aecf4b23873b2299a358301ec24f6c27a5760b 100644 (file)
@@ -57,25 +57,6 @@ void udf_adinicb_readpage(struct page *page)
        kunmap_atomic(kaddr);
 }
 
-static int udf_adinicb_write_begin(struct file *file,
-                       struct address_space *mapping, loff_t pos,
-                       unsigned len, struct page **pagep,
-                       void **fsdata)
-{
-       struct page *page;
-
-       if (WARN_ON_ONCE(pos >= PAGE_SIZE))
-               return -EIO;
-       page = grab_cache_page_write_begin(mapping, 0);
-       if (!page)
-               return -ENOMEM;
-       *pagep = page;
-
-       if (!PageUptodate(page))
-               udf_adinicb_readpage(page);
-       return 0;
-}
-
 static int udf_adinicb_write_end(struct file *file, struct address_space *mapping,
                                 loff_t pos, unsigned len, unsigned copied,
                                 struct page *page, void *fsdata)
@@ -95,7 +76,7 @@ const struct address_space_operations udf_adinicb_aops = {
        .invalidate_folio = block_invalidate_folio,
        .read_folio     = udf_read_folio,
        .writepages     = udf_writepages,
-       .write_begin    = udf_adinicb_write_begin,
+       .write_begin    = udf_write_begin,
        .write_end      = udf_adinicb_write_end,
        .direct_IO      = udf_direct_IO,
 };
index d01b97e9e4f4bffa251538f1a20b1dbf72bbb6d6..afe061d2020e3aeb97054601397c70e6a0ab3289 100644 (file)
@@ -231,16 +231,30 @@ static void udf_readahead(struct readahead_control *rac)
        mpage_readahead(rac, udf_get_block);
 }
 
-static int udf_write_begin(struct file *file, struct address_space *mapping,
+int udf_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len,
                        struct page **pagep, void **fsdata)
 {
+       struct udf_inode_info *iinfo = UDF_I(file_inode(file));
+       struct page *page;
        int ret;
 
-       ret = block_write_begin(mapping, pos, len, pagep, udf_get_block);
-       if (unlikely(ret))
-               udf_write_failed(mapping, pos + len);
-       return ret;
+       if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+               ret = block_write_begin(mapping, pos, len, pagep,
+                                       udf_get_block);
+               if (unlikely(ret))
+                       udf_write_failed(mapping, pos + len);
+               return ret;
+       }
+       if (WARN_ON_ONCE(pos >= PAGE_SIZE))
+               return -EIO;
+       page = grab_cache_page_write_begin(mapping, 0);
+       if (!page)
+               return -ENOMEM;
+       *pagep = page;
+       if (!PageUptodate(page))
+               udf_adinicb_readpage(page);
+       return 0;
 }
 
 ssize_t udf_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
index a851613465c6bdac54345a944596a0f00f9a10ba..32decf6b6a21d8e97aae1f6c6b23c340a0f79ea4 100644 (file)
@@ -161,6 +161,9 @@ extern void udf_evict_inode(struct inode *);
 extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
 int udf_read_folio(struct file *file, struct folio *folio);
 int udf_writepages(struct address_space *mapping, struct writeback_control *wbc);
+int udf_write_begin(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len,
+                       struct page **pagep, void **fsdata);
 ssize_t udf_direct_IO(struct kiocb *iocb, struct iov_iter *iter);
 extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
                         struct kernel_lb_addr *, uint32_t *, sector_t *);