diff options
Diffstat (limited to 'fs/ufs/inode.c')
| -rw-r--r-- | fs/ufs/inode.c | 281 |
1 files changed, 131 insertions, 150 deletions
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 21a4779a2de5..e2b0a35de2a7 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -35,6 +35,7 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/buffer_head.h> +#include <linux/mpage.h> #include <linux/writeback.h> #include <linux/iversion.h> @@ -219,7 +220,7 @@ changed: */ static bool ufs_extend_tail(struct inode *inode, u64 writes_to, - int *err, struct page *locked_page) + int *err, struct folio *locked_folio) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; @@ -238,7 +239,7 @@ ufs_extend_tail(struct inode *inode, u64 writes_to, p = ufs_get_direct_data_ptr(uspi, ufsi, block); tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p), new_size - (lastfrag & uspi->s_fpbmask), err, - locked_page); + locked_folio); return tmp != 0; } @@ -249,12 +250,11 @@ ufs_extend_tail(struct inode *inode, u64 writes_to, * @new_fragment: number of new allocated fragment(s) * @err: we set it if something wrong * @new: we set it if we allocate new block - * @locked_page: for ufs_new_fragments() + * @locked_folio: for ufs_new_fragments() */ -static u64 -ufs_inode_getfrag(struct inode *inode, unsigned index, +static u64 ufs_inode_getfrag(struct inode *inode, unsigned index, sector_t new_fragment, int *err, - int *new, struct page *locked_page) + int *new, struct folio *locked_folio) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; @@ -263,11 +263,6 @@ ufs_inode_getfrag(struct inode *inode, unsigned index, unsigned nfrags = uspi->s_fpb; void *p; - /* TODO : to be done for write support - if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) - goto ufs2; - */ - p = ufs_get_direct_data_ptr(uspi, ufsi, index); tmp = ufs_data_ptr_to_cpu(sb, p); if (tmp) @@ -287,7 +282,7 @@ ufs_inode_getfrag(struct inode *inode, unsigned index, goal += uspi->s_fpb; } tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), - goal, nfrags, err, locked_page); + goal, nfrags, err, locked_folio); if (!tmp) { *err = -ENOSPC; @@ -302,21 +297,6 @@ ufs_inode_getfrag(struct inode *inode, unsigned index, mark_inode_dirty(inode); out: return tmp + uspi->s_sbbase; - - /* This part : To be implemented .... - Required only for writing, not required for READ-ONLY. -ufs2: - - u2_block = ufs_fragstoblks(fragment); - u2_blockoff = ufs_fragnum(fragment); - p = ufsi->i_u1.u2_i_data + block; - goal = 0; - -repeat2: - tmp = fs32_to_cpu(sb, *p); - lastfrag = ufsi->i_lastfrag; - - */ } /** @@ -328,12 +308,11 @@ repeat2: * (block will hold this fragment and also uspi->s_fpb-1) * @err: see ufs_inode_getfrag() * @new: see ufs_inode_getfrag() - * @locked_page: see ufs_inode_getfrag() + * @locked_folio: see ufs_inode_getfrag() */ -static u64 -ufs_inode_getblock(struct inode *inode, u64 ind_block, - unsigned index, sector_t new_fragment, int *err, - int *new, struct page *locked_page) +static u64 ufs_inode_getblock(struct inode *inode, u64 ind_block, + unsigned index, sector_t new_fragment, int *err, + int *new, struct folio *locked_folio) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; @@ -368,7 +347,7 @@ ufs_inode_getblock(struct inode *inode, u64 ind_block, else goal = bh->b_blocknr + uspi->s_fpb; tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, - uspi->s_fpb, err, locked_page); + uspi->s_fpb, err, locked_folio); if (!tmp) goto out; @@ -390,7 +369,7 @@ out: /** * ufs_getfrag_block() - `get_block_t' function, interface between UFS and - * read_folio, writepage and so on + * read_folio, writepages and so on */ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) @@ -433,14 +412,14 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff unsigned tailfrags = lastfrag & uspi->s_fpbmask; if (tailfrags && fragment >= lastfrag) { if (!ufs_extend_tail(inode, fragment, - &err, bh_result->b_page)) + &err, bh_result->b_folio)) goto out; } } if (depth == 1) { phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, - &err, &new, bh_result->b_page); + &err, &new, bh_result->b_folio); } else { int i; phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, @@ -449,7 +428,7 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff phys64 = ufs_inode_getblock(inode, phys64, offsets[i], fragment, &err, NULL, NULL); phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1], - fragment, &err, &new, bh_result->b_page); + fragment, &err, &new, bh_result->b_folio); } out: if (phys64) { @@ -467,9 +446,10 @@ done: return 0; } -static int ufs_writepage(struct page *page, struct writeback_control *wbc) +static int ufs_writepages(struct address_space *mapping, + struct writeback_control *wbc) { - return block_write_full_page(page,ufs_getfrag_block,wbc); + return mpage_writepages(mapping, wbc, ufs_getfrag_block); } static int ufs_read_folio(struct file *file, struct folio *folio) @@ -477,9 +457,9 @@ static int ufs_read_folio(struct file *file, struct folio *folio) return block_read_full_folio(folio, ufs_getfrag_block); } -int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len) +int ufs_prepare_chunk(struct folio *folio, loff_t pos, unsigned len) { - return __block_write_begin(page, pos, len, ufs_getfrag_block); + return __block_write_begin(folio, pos, len, ufs_getfrag_block); } static void ufs_truncate_blocks(struct inode *); @@ -494,26 +474,28 @@ static void ufs_write_failed(struct address_space *mapping, loff_t to) } } -static int ufs_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, - struct page **pagep, void **fsdata) +static int ufs_write_begin(const struct kiocb *iocb, + struct address_space *mapping, + loff_t pos, unsigned len, + struct folio **foliop, void **fsdata) { int ret; - ret = block_write_begin(mapping, pos, len, pagep, ufs_getfrag_block); + ret = block_write_begin(mapping, pos, len, foliop, ufs_getfrag_block); if (unlikely(ret)) ufs_write_failed(mapping, pos + len); return ret; } -static int ufs_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) +static int ufs_write_end(const struct kiocb *iocb, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct folio *folio, void *fsdata) { int ret; - ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); + ret = generic_write_end(iocb, mapping, pos, len, copied, folio, fsdata); if (ret < len) ufs_write_failed(mapping, pos + len); return ret; @@ -528,9 +510,10 @@ const struct address_space_operations ufs_aops = { .dirty_folio = block_dirty_folio, .invalidate_folio = block_invalidate_folio, .read_folio = ufs_read_folio, - .writepage = ufs_writepage, + .writepages = ufs_writepages, .write_begin = ufs_write_begin, .write_end = ufs_write_end, + .migrate_folio = buffer_migrate_folio, .bmap = ufs_bmap }; @@ -579,13 +562,15 @@ static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) i_gid_write(inode, ufs_get_inode_gid(sb, ufs_inode)); inode->i_size = fs64_to_cpu(sb, ufs_inode->ui_size); - inode->i_atime.tv_sec = (signed)fs32_to_cpu(sb, ufs_inode->ui_atime.tv_sec); + inode_set_atime(inode, + (signed)fs32_to_cpu(sb, ufs_inode->ui_atime.tv_sec), + 0); inode_set_ctime(inode, (signed)fs32_to_cpu(sb, ufs_inode->ui_ctime.tv_sec), 0); - inode->i_mtime.tv_sec = (signed)fs32_to_cpu(sb, ufs_inode->ui_mtime.tv_sec); - inode->i_mtime.tv_nsec = 0; - inode->i_atime.tv_nsec = 0; + inode_set_mtime(inode, + (signed)fs32_to_cpu(sb, ufs_inode->ui_mtime.tv_sec), + 0); inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks); inode->i_generation = fs32_to_cpu(sb, ufs_inode->ui_gen); ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags); @@ -626,12 +611,12 @@ static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) i_gid_write(inode, fs32_to_cpu(sb, ufs2_inode->ui_gid)); inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size); - inode->i_atime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_atime); + inode_set_atime(inode, fs64_to_cpu(sb, ufs2_inode->ui_atime), + fs32_to_cpu(sb, ufs2_inode->ui_atimensec)); inode_set_ctime(inode, fs64_to_cpu(sb, ufs2_inode->ui_ctime), fs32_to_cpu(sb, ufs2_inode->ui_ctimensec)); - inode->i_mtime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_mtime); - inode->i_atime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_atimensec); - inode->i_mtime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_mtimensec); + inode_set_mtime(inode, fs64_to_cpu(sb, ufs2_inode->ui_mtime), + fs32_to_cpu(sb, ufs2_inode->ui_mtimensec)); inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks); inode->i_generation = fs32_to_cpu(sb, ufs2_inode->ui_gen); ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags); @@ -670,7 +655,7 @@ struct inode *ufs_iget(struct super_block *sb, unsigned long ino) inode = iget_locked(sb, ino); if (!inode) return ERR_PTR(-ENOMEM); - if (!(inode->i_state & I_NEW)) + if (!(inode_state_read_once(inode) & I_NEW)) return inode; ufsi = UFS_I(inode); @@ -725,12 +710,14 @@ static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode) ufs_set_inode_gid(sb, ufs_inode, i_gid_read(inode)); ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); - ufs_inode->ui_atime.tv_sec = cpu_to_fs32(sb, inode->i_atime.tv_sec); + ufs_inode->ui_atime.tv_sec = cpu_to_fs32(sb, + inode_get_atime_sec(inode)); ufs_inode->ui_atime.tv_usec = 0; ufs_inode->ui_ctime.tv_sec = cpu_to_fs32(sb, - inode_get_ctime(inode).tv_sec); + inode_get_ctime_sec(inode)); ufs_inode->ui_ctime.tv_usec = 0; - ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, inode->i_mtime.tv_sec); + ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, + inode_get_mtime_sec(inode)); ufs_inode->ui_mtime.tv_usec = 0; ufs_inode->ui_blocks = cpu_to_fs32(sb, inode->i_blocks); ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); @@ -770,13 +757,15 @@ static void ufs2_update_inode(struct inode *inode, struct ufs2_inode *ufs_inode) ufs_inode->ui_gid = cpu_to_fs32(sb, i_gid_read(inode)); ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); - ufs_inode->ui_atime = cpu_to_fs64(sb, inode->i_atime.tv_sec); - ufs_inode->ui_atimensec = cpu_to_fs32(sb, inode->i_atime.tv_nsec); - ufs_inode->ui_ctime = cpu_to_fs64(sb, inode_get_ctime(inode).tv_sec); + ufs_inode->ui_atime = cpu_to_fs64(sb, inode_get_atime_sec(inode)); + ufs_inode->ui_atimensec = cpu_to_fs32(sb, + inode_get_atime_nsec(inode)); + ufs_inode->ui_ctime = cpu_to_fs64(sb, inode_get_ctime_sec(inode)); ufs_inode->ui_ctimensec = cpu_to_fs32(sb, - inode_get_ctime(inode).tv_nsec); - ufs_inode->ui_mtime = cpu_to_fs64(sb, inode->i_mtime.tv_sec); - ufs_inode->ui_mtimensec = cpu_to_fs32(sb, inode->i_mtime.tv_nsec); + inode_get_ctime_nsec(inode)); + ufs_inode->ui_mtime = cpu_to_fs64(sb, inode_get_mtime_sec(inode)); + ufs_inode->ui_mtimensec = cpu_to_fs32(sb, + inode_get_mtime_nsec(inode)); ufs_inode->ui_blocks = cpu_to_fs64(sb, inode->i_blocks); ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); @@ -889,91 +878,84 @@ static inline void free_data(struct to_free *ctx, u64 from, unsigned count) #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) +/* + * used only for truncation down to direct blocks. + */ static void ufs_trunc_direct(struct inode *inode) { struct ufs_inode_info *ufsi = UFS_I(inode); - struct super_block * sb; - struct ufs_sb_private_info * uspi; - void *p; - u64 frag1, frag2, frag3, frag4, block1, block2; + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + unsigned int new_frags, old_frags; + unsigned int old_slot, new_slot; + unsigned int old_tail, new_tail; struct to_free ctx = {.inode = inode}; - unsigned i, tmp; UFSD("ENTER: ino %lu\n", inode->i_ino); - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - - frag1 = DIRECT_FRAGMENT; - frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); - frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); - frag3 = frag4 & ~uspi->s_fpbmask; - block1 = block2 = 0; - if (frag2 > frag3) { - frag2 = frag4; - frag3 = frag4 = 0; - } else if (frag2 < frag3) { - block1 = ufs_fragstoblks (frag2); - block2 = ufs_fragstoblks (frag3); - } + new_frags = DIRECT_FRAGMENT; + // new_frags = first fragment past the new EOF + old_frags = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); + // old_frags = first fragment past the old EOF or covered by indirects - UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu," - " frag3 %llu, frag4 %llu\n", inode->i_ino, - (unsigned long long)frag1, (unsigned long long)frag2, - (unsigned long long)block1, (unsigned long long)block2, - (unsigned long long)frag3, (unsigned long long)frag4); - - if (frag1 >= frag2) - goto next1; - - /* - * Free first free fragments - */ - p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1)); - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp ) - ufs_panic (sb, "ufs_trunc_direct", "internal error"); - frag2 -= frag1; - frag1 = ufs_fragnum (frag1); + if (new_frags >= old_frags) // expanding - nothing to free + goto done; - ufs_free_fragments(inode, tmp + frag1, frag2); + old_tail = ufs_fragnum(old_frags); + old_slot = ufs_fragstoblks(old_frags); + new_tail = ufs_fragnum(new_frags); + new_slot = ufs_fragstoblks(new_frags); -next1: - /* - * Free whole blocks - */ - for (i = block1 ; i < block2; i++) { - p = ufs_get_direct_data_ptr(uspi, ufsi, i); - tmp = ufs_data_ptr_to_cpu(sb, p); + if (old_slot == new_slot) { // old_tail > 0 + void *p = ufs_get_direct_data_ptr(uspi, ufsi, old_slot); + u64 tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) - continue; - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); + ufs_panic(sb, __func__, "internal error"); + if (!new_tail) { + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + } + ufs_free_fragments(inode, tmp + new_tail, old_tail - new_tail); + } else { + unsigned int slot = new_slot; - free_data(&ctx, tmp, uspi->s_fpb); - } + if (new_tail) { + void *p = ufs_get_direct_data_ptr(uspi, ufsi, slot++); + u64 tmp = ufs_data_ptr_to_cpu(sb, p); + if (!tmp) + ufs_panic(sb, __func__, "internal error"); - free_data(&ctx, 0, 0); + ufs_free_fragments(inode, tmp + new_tail, + uspi->s_fpb - new_tail); + } + while (slot < old_slot) { + void *p = ufs_get_direct_data_ptr(uspi, ufsi, slot++); + u64 tmp = ufs_data_ptr_to_cpu(sb, p); + if (!tmp) + continue; + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); - if (frag3 >= frag4) - goto next3; + free_data(&ctx, tmp, uspi->s_fpb); + } - /* - * Free last free fragments - */ - p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3)); - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp ) - ufs_panic(sb, "ufs_truncate_direct", "internal error"); - frag4 = ufs_fragnum (frag4); - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); + free_data(&ctx, 0, 0); - ufs_free_fragments (inode, tmp, frag4); - next3: + if (old_tail) { + void *p = ufs_get_direct_data_ptr(uspi, ufsi, slot); + u64 tmp = ufs_data_ptr_to_cpu(sb, p); + if (!tmp) + ufs_panic(sb, __func__, "internal error"); + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + ufs_free_fragments(inode, tmp, old_tail); + } + } +done: UFSD("EXIT: ino %lu\n", inode->i_ino); } @@ -1057,7 +1039,7 @@ static int ufs_alloc_lastblock(struct inode *inode, loff_t size) struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; unsigned i, end; sector_t lastfrag; - struct page *lastpage; + struct folio *folio; struct buffer_head *bh; u64 phys64; @@ -1068,18 +1050,17 @@ static int ufs_alloc_lastblock(struct inode *inode, loff_t size) lastfrag--; - lastpage = ufs_get_locked_page(mapping, lastfrag >> + folio = ufs_get_locked_folio(mapping, lastfrag >> (PAGE_SHIFT - inode->i_blkbits)); - if (IS_ERR(lastpage)) { - err = -EIO; - goto out; - } - - end = lastfrag & ((1 << (PAGE_SHIFT - inode->i_blkbits)) - 1); - bh = page_buffers(lastpage); - for (i = 0; i < end; ++i) - bh = bh->b_this_page; + if (IS_ERR(folio)) { + err = -EIO; + goto out; + } + end = lastfrag & ((1 << (PAGE_SHIFT - inode->i_blkbits)) - 1); + bh = folio_buffers(folio); + for (i = 0; i < end; ++i) + bh = bh->b_this_page; err = ufs_getfrag_block(inode, lastfrag, bh, 1); @@ -1095,7 +1076,7 @@ static int ufs_alloc_lastblock(struct inode *inode, loff_t size) */ set_buffer_uptodate(bh); mark_buffer_dirty(bh); - set_page_dirty(lastpage); + folio_mark_dirty(folio); } if (lastfrag >= UFS_IND_FRAGMENT) { @@ -1113,7 +1094,7 @@ static int ufs_alloc_lastblock(struct inode *inode, loff_t size) } } out_unlock: - ufs_put_locked_page(lastpage); + ufs_put_locked_folio(folio); out: return err; } @@ -1208,7 +1189,7 @@ static int ufs_truncate(struct inode *inode, loff_t size) truncate_setsize(inode, size); ufs_truncate_blocks(inode); - inode->i_mtime = inode_set_ctime_current(inode); + inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); mark_inode_dirty(inode); out: UFSD("EXIT: err %d\n", err); |
