@@ -31,34 +31,77 @@ static void hfsplus_end_io_sync(struct bio *bio, int err)
3131 complete (bio -> bi_private );
3232}
3333
34- int hfsplus_submit_bio (struct block_device * bdev , sector_t sector ,
35- void * data , int rw )
34+ /*
35+ * hfsplus_submit_bio - Perfrom block I/O
36+ * @sb: super block of volume for I/O
37+ * @sector: block to read or write, for blocks of HFSPLUS_SECTOR_SIZE bytes
38+ * @buf: buffer for I/O
39+ * @data: output pointer for location of requested data
40+ * @rw: direction of I/O
41+ *
42+ * The unit of I/O is hfsplus_min_io_size(sb), which may be bigger than
43+ * HFSPLUS_SECTOR_SIZE, and @buf must be sized accordingly. On reads
44+ * @data will return a pointer to the start of the requested sector,
45+ * which may not be the same location as @buf.
46+ *
47+ * If @sector is not aligned to the bdev logical block size it will
48+ * be rounded down. For writes this means that @buf should contain data
49+ * that starts at the rounded-down address. As long as the data was
50+ * read using hfsplus_submit_bio() and the same buffer is used things
51+ * will work correctly.
52+ */
53+ int hfsplus_submit_bio (struct super_block * sb , sector_t sector ,
54+ void * buf , void * * data , int rw )
3655{
3756 DECLARE_COMPLETION_ONSTACK (wait );
3857 struct bio * bio ;
3958 int ret = 0 ;
59+ unsigned int io_size ;
60+ loff_t start ;
61+ int offset ;
62+
63+ /*
64+ * Align sector to hardware sector size and find offset. We
65+ * assume that io_size is a power of two, which _should_
66+ * be true.
67+ */
68+ io_size = hfsplus_min_io_size (sb );
69+ start = (loff_t )sector << HFSPLUS_SECTOR_SHIFT ;
70+ offset = start & (io_size - 1 );
71+ sector &= ~((io_size >> HFSPLUS_SECTOR_SHIFT ) - 1 );
4072
4173 bio = bio_alloc (GFP_NOIO , 1 );
4274 bio -> bi_sector = sector ;
43- bio -> bi_bdev = bdev ;
75+ bio -> bi_bdev = sb -> s_bdev ;
4476 bio -> bi_end_io = hfsplus_end_io_sync ;
4577 bio -> bi_private = & wait ;
4678
47- /*
48- * We always submit one sector at a time, so bio_add_page must not fail.
49- */
50- if (bio_add_page (bio , virt_to_page (data ), HFSPLUS_SECTOR_SIZE ,
51- offset_in_page (data )) != HFSPLUS_SECTOR_SIZE )
52- BUG ();
79+ if (!(rw & WRITE ) && data )
80+ * data = (u8 * )buf + offset ;
81+
82+ while (io_size > 0 ) {
83+ unsigned int page_offset = offset_in_page (buf );
84+ unsigned int len = min_t (unsigned int , PAGE_SIZE - page_offset ,
85+ io_size );
86+
87+ ret = bio_add_page (bio , virt_to_page (buf ), len , page_offset );
88+ if (ret != len ) {
89+ ret = - EIO ;
90+ goto out ;
91+ }
92+ io_size -= len ;
93+ buf = (u8 * )buf + len ;
94+ }
5395
5496 submit_bio (rw , bio );
5597 wait_for_completion (& wait );
5698
5799 if (!bio_flagged (bio , BIO_UPTODATE ))
58100 ret = - EIO ;
59101
102+ out :
60103 bio_put (bio );
61- return ret ;
104+ return ret < 0 ? ret : 0 ;
62105}
63106
64107static int hfsplus_read_mdb (void * bufptr , struct hfsplus_wd * wd )
@@ -143,17 +186,17 @@ int hfsplus_read_wrapper(struct super_block *sb)
143186 goto out ;
144187
145188 error = - ENOMEM ;
146- sbi -> s_vhdr = kmalloc (HFSPLUS_SECTOR_SIZE , GFP_KERNEL );
147- if (!sbi -> s_vhdr )
189+ sbi -> s_vhdr_buf = kmalloc (hfsplus_min_io_size ( sb ) , GFP_KERNEL );
190+ if (!sbi -> s_vhdr_buf )
148191 goto out ;
149- sbi -> s_backup_vhdr = kmalloc (HFSPLUS_SECTOR_SIZE , GFP_KERNEL );
150- if (!sbi -> s_backup_vhdr )
192+ sbi -> s_backup_vhdr_buf = kmalloc (hfsplus_min_io_size ( sb ) , GFP_KERNEL );
193+ if (!sbi -> s_backup_vhdr_buf )
151194 goto out_free_vhdr ;
152195
153196reread :
154- error = hfsplus_submit_bio (sb -> s_bdev ,
155- part_start + HFSPLUS_VOLHEAD_SECTOR ,
156- sbi -> s_vhdr , READ );
197+ error = hfsplus_submit_bio (sb , part_start + HFSPLUS_VOLHEAD_SECTOR ,
198+ sbi -> s_vhdr_buf , ( void * * ) & sbi -> s_vhdr ,
199+ READ );
157200 if (error )
158201 goto out_free_backup_vhdr ;
159202
@@ -183,9 +226,9 @@ int hfsplus_read_wrapper(struct super_block *sb)
183226 goto reread ;
184227 }
185228
186- error = hfsplus_submit_bio (sb -> s_bdev ,
187- part_start + part_size - 2 ,
188- sbi -> s_backup_vhdr , READ );
229+ error = hfsplus_submit_bio (sb , part_start + part_size - 2 ,
230+ sbi -> s_backup_vhdr_buf ,
231+ ( void * * ) & sbi -> s_backup_vhdr , READ );
189232 if (error )
190233 goto out_free_backup_vhdr ;
191234
0 commit comments