From: Shiyong Li Date: Sat, 9 Dec 2017 01:27:12 +0000 (-0800) Subject: fs/exfat: implement errors=remount-ro X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=7d071306bde0b7f8c023d6ca3b7a2bbac31b7015;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git fs/exfat: implement errors=remount-ro 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 Reviewed-on: https://gerrit.mot.com/1102176 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Igor Kovalenko Submit-Approved: Jira Key Reviewed-on: https://gerrit.mot.com/1276877 Reviewed-by: Hua Tan --- diff --git a/fs/exfat/exfat_blkdev.c b/fs/exfat/exfat_blkdev.c index eaccfd84e9f9..e3280fd35b71 100644 --- a/fs/exfat/exfat_blkdev.c +++ b/fs/exfat/exfat_blkdev.c @@ -126,6 +126,50 @@ s32 bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, u 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; @@ -148,7 +192,7 @@ s32 bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, u 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; @@ -163,7 +207,7 @@ s32 bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, u 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; } @@ -193,5 +237,8 @@ s32 bdev_sync(struct super_block *sb) if (!p_bd->opened) return FFS_MEDIAERR; + if (exfat_readonly(sb)) + return FFS_MEDIAERR; + return sync_blockdev(sb->s_bdev); } diff --git a/fs/exfat/exfat_blkdev.h b/fs/exfat/exfat_blkdev.h index 3363b591caeb..3082f221f2e4 100644 --- a/fs/exfat/exfat_blkdev.h +++ b/fs/exfat/exfat_blkdev.h @@ -69,5 +69,8 @@ s32 bdev_close(struct super_block *sb); 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 */ diff --git a/fs/exfat/exfat_cache.c b/fs/exfat/exfat_cache.c index 4130102e3739..0a8611601546 100644 --- a/fs/exfat/exfat_cache.c +++ b/fs/exfat/exfat_cache.c @@ -686,7 +686,7 @@ void buf_sync(struct super_block *sb) 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; diff --git a/fs/exfat/exfat_core.c b/fs/exfat/exfat_core.c index 143b72155ef9..6254d03e430d 100644 --- a/fs/exfat/exfat_core.c +++ b/fs/exfat/exfat_core.c @@ -2314,7 +2314,7 @@ void sync_alloc_bitmap(struct super_block *sb) 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 */ /* diff --git a/fs/exfat/exfat_super.c b/fs/exfat/exfat_super.c index ab828c37468e..7961d1fe612b 100644 --- a/fs/exfat/exfat_super.c +++ b/fs/exfat/exfat_super.c @@ -1616,17 +1616,18 @@ static int exfat_readpages(struct file *file, struct address_space *mapping, 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) @@ -2067,7 +2068,7 @@ static void exfat_write_super(struct super_block *sb) __set_sb_clean(sb); - if (!(sb->s_flags & MS_RDONLY)) + if (!exfat_readonly(sb)) FsSyncVol(sb, 1); __unlock_super(sb); diff --git a/fs/exfat/exfat_super.h b/fs/exfat/exfat_super.h index 916811e3d31e..f647daa41b26 100644 --- a/fs/exfat/exfat_super.h +++ b/fs/exfat/exfat_super.h @@ -117,6 +117,11 @@ static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) 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.