This patch implements errors=remount-ro for exfat.
Port of
cf4fa60 and
58ec900 on 8996 with minor change for
updated submit_io() interface in kernel 4.9.
Change-Id: Iee791a99216ecf9f710adffa681706e761f97d8f
Signed-off-by: Shiyong Li <a22381@motorola.com>
Reviewed-on: https://gerrit.mot.com/
1102176
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Igor Kovalenko <igork@motorola.com>
Submit-Approved: Jira Key
Reviewed-on: https://gerrit.mot.com/
1276877
Reviewed-by: Hua Tan <tanhua1@motorola.com>
return FFS_MEDIAERR;
}
+void bdev_end_buffer_write(struct buffer_head *bh, int uptodate, int sync)
+{
+ if (!uptodate)
+ fs_error(bh->b_private);
+
+ if (sync)
+ end_buffer_write_sync(bh, uptodate);
+ else
+ end_buffer_async_write(bh, uptodate);
+}
+
+static void exfat_end_buffer_write_sync(struct buffer_head *bh, int uptodate)
+{
+ bdev_end_buffer_write(bh, uptodate, 1);
+}
+
+s32 bdev_sync_dirty_buffer(struct buffer_head *bh,
+ struct super_block *sb, int sync)
+{
+ int ret = 0;
+
+ WARN_ON(atomic_read(&bh->b_count) < 1);
+ lock_buffer(bh);
+ if (test_clear_buffer_dirty(bh)) {
+ if (exfat_readonly(sb)) {
+ unlock_buffer(bh);
+ return 0;
+ }
+
+ get_bh(bh);
+ bh->b_private = sb;
+ bh->b_end_io = exfat_end_buffer_write_sync;
+ ret = submit_bh(REQ_OP_WRITE, WRITE_SYNC, bh);
+ if (sync) {
+ wait_on_buffer(bh);
+ if (!ret && !buffer_uptodate(bh))
+ ret = -EIO;
+ }
+ } else {
+ unlock_buffer(bh);
+ }
+ return ret;
+}
+
s32 bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, u32 num_secs, s32 sync)
{
s32 count;
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
unlock_buffer(bh);
- if (sync && (sync_dirty_buffer(bh) != 0))
+ if (bdev_sync_dirty_buffer(bh, sb, sync))
return FFS_MEDIAERR;
} else {
count = num_secs << p_bd->sector_size_bits;
set_buffer_uptodate(bh2);
mark_buffer_dirty(bh2);
unlock_buffer(bh2);
- if (sync && (sync_dirty_buffer(bh2) != 0)) {
+ if (bdev_sync_dirty_buffer(bh2, sb, sync)) {
__brelse(bh2);
goto no_bh;
}
if (!p_bd->opened)
return FFS_MEDIAERR;
+ if (exfat_readonly(sb))
+ return FFS_MEDIAERR;
+
return sync_blockdev(sb->s_bdev);
}
s32 bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, u32 num_secs, s32 read);
s32 bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, u32 num_secs, s32 sync);
s32 bdev_sync(struct super_block *sb);
+void bdev_end_buffer_write(struct buffer_head *bh, int uptodate, int sync);
+s32 bdev_sync_dirty_buffer(struct buffer_head *bh,
+ struct super_block *sb, int sync);
#endif /* _EXFAT_BLKDEV_H */
bp = p_fs->buf_cache_lru_list.next;
while (bp != &p_fs->buf_cache_lru_list) {
if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) {
- sync_dirty_buffer(bp->buf_bh);
+ bdev_sync_dirty_buffer(bp->buf_bh, sb, 1);
bp->flag &= ~(DIRTYBIT);
}
bp = bp->next;
return;
for (i = 0; i < p_fs->map_sectors; i++)
- sync_dirty_buffer(p_fs->vol_amap[i]);
+ bdev_sync_dirty_buffer(p_fs->vol_amap[i], sb, 1);
} /* end of sync_alloc_bitmap */
/*
static int exfat_writepage(struct page *page, struct writeback_control *wbc)
{
- int ret;
- ret = block_write_full_page(page, exfat_get_block, wbc);
- return ret;
+ if (exfat_readonly(page->mapping->host->i_sb))
+ return -EROFS;
+ return block_write_full_page(page, exfat_get_block, wbc);
}
static int exfat_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
- int ret;
- ret = mpage_writepages(mapping, wbc, exfat_get_block);
- return ret;
+ if (exfat_readonly(mapping->host->i_sb))
+ return -EROFS;
+ /* get_block should be NULL to call ->writepage and catch end_io */
+ return mpage_writepages(mapping, wbc, NULL);
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
__set_sb_clean(sb);
- if (!(sb->s_flags & MS_RDONLY))
+ if (!exfat_readonly(sb))
FsSyncVol(sb, 1);
__unlock_super(sb);
return container_of(inode, struct exfat_inode_info, vfs_inode);
}
+static inline bool exfat_readonly(struct super_block *sb)
+{
+ return sb->s_flags & MS_RDONLY;
+}
+
/*
* If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to
* save ATTR_RO instead of ->i_mode.