fs/exfat: implement errors=remount-ro
authorShiyong Li <a22381@motorola.com>
Sat, 9 Dec 2017 01:27:12 +0000 (17:27 -0800)
committerxiest1 <xiest1@lenovo.com>
Tue, 5 Nov 2019 09:30:25 +0000 (17:30 +0800)
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>
fs/exfat/exfat_blkdev.c
fs/exfat/exfat_blkdev.h
fs/exfat/exfat_cache.c
fs/exfat/exfat_core.c
fs/exfat/exfat_super.c
fs/exfat/exfat_super.h

index eaccfd84e9f9bf12ec2adaa8251d9915563c3986..e3280fd35b71fe6741d150180918ccc377c08342 100644 (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);
 }
index 3363b591caebca468554b32b9cdd0b91e492dcca..3082f221f2e4467914f158bab6303b911510a595 100644 (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 */
index 4130102e373929de339c563ca95652a1db2ab73c..0a8611601546795a1f764678ba698b90ece0fcc8 100644 (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;
index 143b72155ef9e075c215ff1b5ecbb22cbfeff61a..6254d03e430de7dd12c16520424ff78d5254df64 100644 (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 */
 
 /*
index ab828c37468e3a4ed6de0e10292c85b53c631517..7961d1fe612be4e05db5d1b5ccf341b4d5079b21 100644 (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);
index 916811e3d31e24f8418ec1a08296db8d4e7574cc..f647daa41b261f2ec3a6bbae78f5bd9be657c55c 100644 (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.