udf: Convert in-ICB files to use udf_writepages()
authorJan Kara <jack@suse.cz>
Tue, 24 Jan 2023 10:54:08 +0000 (11:54 +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_writepages().

Reported-by: syzbot+c27475eb921c46bbdc62@syzkaller.appspotmail.com
Reported-by: Christoph Hellwig <hch@lst.de>
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 2666234a5204d83926d3a230b9fd2f3df2c40831..7a8dbad86e414340573bb5e7989d160f495f0327 100644 (file)
@@ -57,25 +57,6 @@ void udf_adinicb_readpage(struct page *page)
        kunmap_atomic(kaddr);
 }
 
-static int udf_adinicb_writepage(struct page *page,
-                                struct writeback_control *wbc)
-{
-       struct inode *inode = page->mapping->host;
-       char *kaddr;
-       struct udf_inode_info *iinfo = UDF_I(inode);
-
-       BUG_ON(!PageLocked(page));
-
-       kaddr = kmap_atomic(page);
-       memcpy(iinfo->i_data + iinfo->i_lenEAttr, kaddr, i_size_read(inode));
-       SetPageUptodate(page);
-       kunmap_atomic(kaddr);
-       mark_inode_dirty(inode);
-       unlock_page(page);
-
-       return 0;
-}
-
 static int udf_adinicb_write_begin(struct file *file,
                        struct address_space *mapping, loff_t pos,
                        unsigned len, struct page **pagep,
@@ -119,7 +100,7 @@ const struct address_space_operations udf_adinicb_aops = {
        .dirty_folio    = block_dirty_folio,
        .invalidate_folio = block_invalidate_folio,
        .read_folio     = udf_read_folio,
-       .writepage      = udf_adinicb_writepage,
+       .writepages     = udf_writepages,
        .write_begin    = udf_adinicb_write_begin,
        .write_end      = udf_adinicb_write_end,
        .direct_IO      = udf_adinicb_direct_IO,
index a1816f067c14a23f4df3b223a7567038c0d511b8..f0ab4dd0d8ce6d0ec2364141812441a716d693b5 100644 (file)
@@ -185,10 +185,33 @@ static void udf_write_failed(struct address_space *mapping, loff_t to)
        }
 }
 
-static int udf_writepages(struct address_space *mapping,
-                       struct writeback_control *wbc)
+static int udf_adinicb_writepage(struct page *page,
+                                struct writeback_control *wbc, void *data)
 {
-       return mpage_writepages(mapping, wbc, udf_get_block_wb);
+       struct inode *inode = page->mapping->host;
+       char *kaddr;
+       struct udf_inode_info *iinfo = UDF_I(inode);
+
+       BUG_ON(!PageLocked(page));
+
+       kaddr = kmap_atomic(page);
+       memcpy(iinfo->i_data + iinfo->i_lenEAttr, kaddr, i_size_read(inode));
+       SetPageUptodate(page);
+       kunmap_atomic(kaddr);
+       unlock_page(page);
+       mark_inode_dirty(inode);
+
+       return 0;
+}
+
+int udf_writepages(struct address_space *mapping, struct writeback_control *wbc)
+{
+       struct inode *inode = mapping->host;
+       struct udf_inode_info *iinfo = UDF_I(inode);
+
+       if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB)
+               return mpage_writepages(mapping, wbc, udf_get_block_wb);
+       return write_cache_pages(mapping, wbc, udf_adinicb_writepage, NULL);
 }
 
 int udf_read_folio(struct file *file, struct folio *folio)
index 6b93b393cb467f1890c98931c7b6231613f80131..48647eab26a6325bd94cd502a9bdf0235c363558 100644 (file)
@@ -160,6 +160,7 @@ extern int udf_setsize(struct inode *, loff_t);
 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);
 extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
                         struct kernel_lb_addr *, uint32_t *, sector_t *);
 int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);