2020-06-04 17:44 GMT+09:00, Tetsuhiro Kohada <kohada.t2@xxxxxxxxx>: Hi Tetsuhiro, > Add error check when synchronously updating dir-entries. > Furthermore, add exfat_update_bhs(). It wait for write completion once > instead of sector by sector. This patch can be split into two also ? > > Suggested-by: Sungjong Seo <sj1557.seo@xxxxxxxxxxx> > Signed-off-by: Tetsuhiro Kohada <kohada.t2@xxxxxxxxx> > --- > fs/exfat/dir.c | 15 +++++++++------ > fs/exfat/exfat_fs.h | 3 ++- > fs/exfat/file.c | 5 ++++- > fs/exfat/inode.c | 8 +++++--- > fs/exfat/misc.c | 19 +++++++++++++++++++ > 5 files changed, 39 insertions(+), 11 deletions(-) > > diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c > index de43534aa299..3eb8386fb5f2 100644 > --- a/fs/exfat/dir.c > +++ b/fs/exfat/dir.c > @@ -602,16 +602,19 @@ void exfat_update_dir_chksum_with_entry_set(struct > exfat_entry_set_cache *es) > es->modified = true; > } > > -void exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync) > +int exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync) > { > - int i; > + int i, err = 0; > > - for (i = 0; i < es->num_bh; i++) { > - if (es->modified) > - exfat_update_bh(es->sb, es->bh[i], sync); > - brelse(es->bh[i]); > + if (es->modified) { > + set_bit(EXFAT_SB_DIRTY, &EXFAT_SB(es->sb)->s_state); EXFAT_SB_DIRTY set can be merged into exfat_update_bhs() ? > + err = exfat_update_bhs(es->bh, es->num_bh, sync); > } > + > + for (i = 0; i < es->num_bh; i++) > + err ? bforget(es->bh[i]):brelse(es->bh[i]); > kfree(es); > + return err; > } > > static int exfat_walk_fat_chain(struct super_block *sb, > diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h > index 595f3117f492..f4fa0e833486 100644 > --- a/fs/exfat/exfat_fs.h > +++ b/fs/exfat/exfat_fs.h > @@ -462,7 +462,7 @@ struct exfat_dentry *exfat_get_dentry_cached(struct > exfat_entry_set_cache *es, > int num); > struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, > struct exfat_chain *p_dir, int entry, unsigned int type); > -void exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync); > +int exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync); > int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain > *p_dir); > > /* inode.c */ > @@ -515,6 +515,7 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, > struct timespec64 *ts, > u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type); > u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type); > void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int > sync); > +int exfat_update_bhs(struct buffer_head **bhs, int nr_bhs, int sync); > void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, > unsigned int size, unsigned char flags); > void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec); > diff --git a/fs/exfat/file.c b/fs/exfat/file.c > index fce03f318787..37c8f04c1f8a 100644 > --- a/fs/exfat/file.c > +++ b/fs/exfat/file.c > @@ -153,6 +153,7 @@ int __exfat_truncate(struct inode *inode, loff_t > new_size) > struct timespec64 ts; > struct exfat_dentry *ep, *ep2; > struct exfat_entry_set_cache *es; > + int err; > > es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, > ES_ALL_ENTRIES); > @@ -187,7 +188,9 @@ int __exfat_truncate(struct inode *inode, loff_t > new_size) > } > > exfat_update_dir_chksum_with_entry_set(es); > - exfat_free_dentry_set(es, inode_needs_sync(inode)); > + err = exfat_free_dentry_set(es, inode_needs_sync(inode)); > + if (err) > + return err; > } > > /* cut off from the FAT chain */ > diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c > index ef7cf7a6d187..c0bfd1a586aa 100644 > --- a/fs/exfat/inode.c > +++ b/fs/exfat/inode.c > @@ -77,8 +77,7 @@ static int __exfat_write_inode(struct inode *inode, int > sync) > ep2->dentry.stream.size = ep2->dentry.stream.valid_size; > > exfat_update_dir_chksum_with_entry_set(es); > - exfat_free_dentry_set(es, sync); > - return 0; > + return exfat_free_dentry_set(es, sync); > } > > int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) > @@ -222,6 +221,7 @@ static int exfat_map_cluster(struct inode *inode, > unsigned int clu_offset, > if (ei->dir.dir != DIR_DELETED && modified) { > struct exfat_dentry *ep; > struct exfat_entry_set_cache *es; > + int err; > > es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, > ES_ALL_ENTRIES); > @@ -240,7 +240,9 @@ static int exfat_map_cluster(struct inode *inode, > unsigned int clu_offset, > ep->dentry.stream.valid_size; > > exfat_update_dir_chksum_with_entry_set(es); > - exfat_free_dentry_set(es, inode_needs_sync(inode)); > + err = exfat_free_dentry_set(es, inode_needs_sync(inode)); > + if (err) > + return err; > > } /* end of if != DIR_DELETED */ > > diff --git a/fs/exfat/misc.c b/fs/exfat/misc.c > index 17d41f3d3709..dc34968e99d3 100644 > --- a/fs/exfat/misc.c > +++ b/fs/exfat/misc.c > @@ -173,6 +173,25 @@ void exfat_update_bh(struct super_block *sb, struct > buffer_head *bh, int sync) > sync_dirty_buffer(bh); > } > > +int exfat_update_bhs(struct buffer_head **bhs, int nr_bhs, int sync) > +{ > + int i, err = 0; > + > + for (i = 0; i < nr_bhs; i++) { > + set_buffer_uptodate(bhs[i]); > + mark_buffer_dirty(bhs[i]); > + if (sync) > + write_dirty_buffer(bhs[i], 0); > + } > + > + for (i = 0; i < nr_bhs && sync; i++) { > + wait_on_buffer(bhs[i]); > + if (!buffer_uptodate(bhs[i])) > + err = -EIO; > + } > + return err; > +} > + > void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, > unsigned int size, unsigned char flags) > { > -- > 2.25.1 > >