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 <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
This commit is contained in:
Shiyong Li 2017-12-08 17:27:12 -08:00 • committed by Shi-Yong Li
commit 982b6998ab
6 changed files with 67 additions and 11 deletions

View file

@ -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);
}

View file

@ -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 */

View file

@ -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;

View file

@ -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 */
/*

View file

@ -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);

View file

@ -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.