162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ufs/inode.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1998 662306a36Sopenharmony_ci * Daniel Pirkl <daniel.pirkl@email.cz> 762306a36Sopenharmony_ci * Charles University, Faculty of Mathematics and Physics 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * from 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * linux/fs/ext2/inode.c 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 1462306a36Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 1562306a36Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal 1662306a36Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI) 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * from 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * linux/fs/minix/inode.c 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 2562306a36Sopenharmony_ci * Big-endian to little-endian byte-swapping/bitmaps by 2662306a36Sopenharmony_ci * David S. Miller (davem@caip.rutgers.edu), 1995 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/uaccess.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/errno.h> 3262306a36Sopenharmony_ci#include <linux/fs.h> 3362306a36Sopenharmony_ci#include <linux/time.h> 3462306a36Sopenharmony_ci#include <linux/stat.h> 3562306a36Sopenharmony_ci#include <linux/string.h> 3662306a36Sopenharmony_ci#include <linux/mm.h> 3762306a36Sopenharmony_ci#include <linux/buffer_head.h> 3862306a36Sopenharmony_ci#include <linux/writeback.h> 3962306a36Sopenharmony_ci#include <linux/iversion.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "ufs_fs.h" 4262306a36Sopenharmony_ci#include "ufs.h" 4362306a36Sopenharmony_ci#include "swab.h" 4462306a36Sopenharmony_ci#include "util.h" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int ufs_block_to_path(struct inode *inode, sector_t i_block, unsigned offsets[4]) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; 4962306a36Sopenharmony_ci int ptrs = uspi->s_apb; 5062306a36Sopenharmony_ci int ptrs_bits = uspi->s_apbshift; 5162306a36Sopenharmony_ci const long direct_blocks = UFS_NDADDR, 5262306a36Sopenharmony_ci indirect_blocks = ptrs, 5362306a36Sopenharmony_ci double_blocks = (1 << (ptrs_bits * 2)); 5462306a36Sopenharmony_ci int n = 0; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); 5862306a36Sopenharmony_ci if (i_block < direct_blocks) { 5962306a36Sopenharmony_ci offsets[n++] = i_block; 6062306a36Sopenharmony_ci } else if ((i_block -= direct_blocks) < indirect_blocks) { 6162306a36Sopenharmony_ci offsets[n++] = UFS_IND_BLOCK; 6262306a36Sopenharmony_ci offsets[n++] = i_block; 6362306a36Sopenharmony_ci } else if ((i_block -= indirect_blocks) < double_blocks) { 6462306a36Sopenharmony_ci offsets[n++] = UFS_DIND_BLOCK; 6562306a36Sopenharmony_ci offsets[n++] = i_block >> ptrs_bits; 6662306a36Sopenharmony_ci offsets[n++] = i_block & (ptrs - 1); 6762306a36Sopenharmony_ci } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { 6862306a36Sopenharmony_ci offsets[n++] = UFS_TIND_BLOCK; 6962306a36Sopenharmony_ci offsets[n++] = i_block >> (ptrs_bits * 2); 7062306a36Sopenharmony_ci offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); 7162306a36Sopenharmony_ci offsets[n++] = i_block & (ptrs - 1); 7262306a36Sopenharmony_ci } else { 7362306a36Sopenharmony_ci ufs_warning(inode->i_sb, "ufs_block_to_path", "block > big"); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci return n; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_citypedef struct { 7962306a36Sopenharmony_ci void *p; 8062306a36Sopenharmony_ci union { 8162306a36Sopenharmony_ci __fs32 key32; 8262306a36Sopenharmony_ci __fs64 key64; 8362306a36Sopenharmony_ci }; 8462306a36Sopenharmony_ci struct buffer_head *bh; 8562306a36Sopenharmony_ci} Indirect; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic inline int grow_chain32(struct ufs_inode_info *ufsi, 8862306a36Sopenharmony_ci struct buffer_head *bh, __fs32 *v, 8962306a36Sopenharmony_ci Indirect *from, Indirect *to) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci Indirect *p; 9262306a36Sopenharmony_ci unsigned seq; 9362306a36Sopenharmony_ci to->bh = bh; 9462306a36Sopenharmony_ci do { 9562306a36Sopenharmony_ci seq = read_seqbegin(&ufsi->meta_lock); 9662306a36Sopenharmony_ci to->key32 = *(__fs32 *)(to->p = v); 9762306a36Sopenharmony_ci for (p = from; p <= to && p->key32 == *(__fs32 *)p->p; p++) 9862306a36Sopenharmony_ci ; 9962306a36Sopenharmony_ci } while (read_seqretry(&ufsi->meta_lock, seq)); 10062306a36Sopenharmony_ci return (p > to); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic inline int grow_chain64(struct ufs_inode_info *ufsi, 10462306a36Sopenharmony_ci struct buffer_head *bh, __fs64 *v, 10562306a36Sopenharmony_ci Indirect *from, Indirect *to) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci Indirect *p; 10862306a36Sopenharmony_ci unsigned seq; 10962306a36Sopenharmony_ci to->bh = bh; 11062306a36Sopenharmony_ci do { 11162306a36Sopenharmony_ci seq = read_seqbegin(&ufsi->meta_lock); 11262306a36Sopenharmony_ci to->key64 = *(__fs64 *)(to->p = v); 11362306a36Sopenharmony_ci for (p = from; p <= to && p->key64 == *(__fs64 *)p->p; p++) 11462306a36Sopenharmony_ci ; 11562306a36Sopenharmony_ci } while (read_seqretry(&ufsi->meta_lock, seq)); 11662306a36Sopenharmony_ci return (p > to); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* 12062306a36Sopenharmony_ci * Returns the location of the fragment from 12162306a36Sopenharmony_ci * the beginning of the filesystem. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic u64 ufs_frag_map(struct inode *inode, unsigned offsets[4], int depth) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 12762306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 12862306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 12962306a36Sopenharmony_ci u64 mask = (u64) uspi->s_apbmask>>uspi->s_fpbshift; 13062306a36Sopenharmony_ci int shift = uspi->s_apbshift-uspi->s_fpbshift; 13162306a36Sopenharmony_ci Indirect chain[4], *q = chain; 13262306a36Sopenharmony_ci unsigned *p; 13362306a36Sopenharmony_ci unsigned flags = UFS_SB(sb)->s_flags; 13462306a36Sopenharmony_ci u64 res = 0; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n", 13762306a36Sopenharmony_ci uspi->s_fpbshift, uspi->s_apbmask, 13862306a36Sopenharmony_ci (unsigned long long)mask); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (depth == 0) 14162306a36Sopenharmony_ci goto no_block; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciagain: 14462306a36Sopenharmony_ci p = offsets; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 14762306a36Sopenharmony_ci goto ufs2; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (!grow_chain32(ufsi, NULL, &ufsi->i_u1.i_data[*p++], chain, q)) 15062306a36Sopenharmony_ci goto changed; 15162306a36Sopenharmony_ci if (!q->key32) 15262306a36Sopenharmony_ci goto no_block; 15362306a36Sopenharmony_ci while (--depth) { 15462306a36Sopenharmony_ci __fs32 *ptr; 15562306a36Sopenharmony_ci struct buffer_head *bh; 15662306a36Sopenharmony_ci unsigned n = *p++; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci bh = sb_bread(sb, uspi->s_sbbase + 15962306a36Sopenharmony_ci fs32_to_cpu(sb, q->key32) + (n>>shift)); 16062306a36Sopenharmony_ci if (!bh) 16162306a36Sopenharmony_ci goto no_block; 16262306a36Sopenharmony_ci ptr = (__fs32 *)bh->b_data + (n & mask); 16362306a36Sopenharmony_ci if (!grow_chain32(ufsi, bh, ptr, chain, ++q)) 16462306a36Sopenharmony_ci goto changed; 16562306a36Sopenharmony_ci if (!q->key32) 16662306a36Sopenharmony_ci goto no_block; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci res = fs32_to_cpu(sb, q->key32); 16962306a36Sopenharmony_ci goto found; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ciufs2: 17262306a36Sopenharmony_ci if (!grow_chain64(ufsi, NULL, &ufsi->i_u1.u2_i_data[*p++], chain, q)) 17362306a36Sopenharmony_ci goto changed; 17462306a36Sopenharmony_ci if (!q->key64) 17562306a36Sopenharmony_ci goto no_block; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci while (--depth) { 17862306a36Sopenharmony_ci __fs64 *ptr; 17962306a36Sopenharmony_ci struct buffer_head *bh; 18062306a36Sopenharmony_ci unsigned n = *p++; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci bh = sb_bread(sb, uspi->s_sbbase + 18362306a36Sopenharmony_ci fs64_to_cpu(sb, q->key64) + (n>>shift)); 18462306a36Sopenharmony_ci if (!bh) 18562306a36Sopenharmony_ci goto no_block; 18662306a36Sopenharmony_ci ptr = (__fs64 *)bh->b_data + (n & mask); 18762306a36Sopenharmony_ci if (!grow_chain64(ufsi, bh, ptr, chain, ++q)) 18862306a36Sopenharmony_ci goto changed; 18962306a36Sopenharmony_ci if (!q->key64) 19062306a36Sopenharmony_ci goto no_block; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci res = fs64_to_cpu(sb, q->key64); 19362306a36Sopenharmony_cifound: 19462306a36Sopenharmony_ci res += uspi->s_sbbase; 19562306a36Sopenharmony_cino_block: 19662306a36Sopenharmony_ci while (q > chain) { 19762306a36Sopenharmony_ci brelse(q->bh); 19862306a36Sopenharmony_ci q--; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci return res; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cichanged: 20362306a36Sopenharmony_ci while (q > chain) { 20462306a36Sopenharmony_ci brelse(q->bh); 20562306a36Sopenharmony_ci q--; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci goto again; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* 21162306a36Sopenharmony_ci * Unpacking tails: we have a file with partial final block and 21262306a36Sopenharmony_ci * we had been asked to extend it. If the fragment being written 21362306a36Sopenharmony_ci * is within the same block, we need to extend the tail just to cover 21462306a36Sopenharmony_ci * that fragment. Otherwise the tail is extended to full block. 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * Note that we might need to create a _new_ tail, but that will 21762306a36Sopenharmony_ci * be handled elsewhere; this is strictly for resizing old 21862306a36Sopenharmony_ci * ones. 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_cistatic bool 22162306a36Sopenharmony_ciufs_extend_tail(struct inode *inode, u64 writes_to, 22262306a36Sopenharmony_ci int *err, struct page *locked_page) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 22562306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 22662306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 22762306a36Sopenharmony_ci unsigned lastfrag = ufsi->i_lastfrag; /* it's a short file, so unsigned is enough */ 22862306a36Sopenharmony_ci unsigned block = ufs_fragstoblks(lastfrag); 22962306a36Sopenharmony_ci unsigned new_size; 23062306a36Sopenharmony_ci void *p; 23162306a36Sopenharmony_ci u64 tmp; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (writes_to < (lastfrag | uspi->s_fpbmask)) 23462306a36Sopenharmony_ci new_size = (writes_to & uspi->s_fpbmask) + 1; 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci new_size = uspi->s_fpb; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, block); 23962306a36Sopenharmony_ci tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p), 24062306a36Sopenharmony_ci new_size - (lastfrag & uspi->s_fpbmask), err, 24162306a36Sopenharmony_ci locked_page); 24262306a36Sopenharmony_ci return tmp != 0; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/** 24662306a36Sopenharmony_ci * ufs_inode_getfrag() - allocate new fragment(s) 24762306a36Sopenharmony_ci * @inode: pointer to inode 24862306a36Sopenharmony_ci * @index: number of block pointer within the inode's array. 24962306a36Sopenharmony_ci * @new_fragment: number of new allocated fragment(s) 25062306a36Sopenharmony_ci * @err: we set it if something wrong 25162306a36Sopenharmony_ci * @new: we set it if we allocate new block 25262306a36Sopenharmony_ci * @locked_page: for ufs_new_fragments() 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_cistatic u64 25562306a36Sopenharmony_ciufs_inode_getfrag(struct inode *inode, unsigned index, 25662306a36Sopenharmony_ci sector_t new_fragment, int *err, 25762306a36Sopenharmony_ci int *new, struct page *locked_page) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 26062306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 26162306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 26262306a36Sopenharmony_ci u64 tmp, goal, lastfrag; 26362306a36Sopenharmony_ci unsigned nfrags = uspi->s_fpb; 26462306a36Sopenharmony_ci void *p; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* TODO : to be done for write support 26762306a36Sopenharmony_ci if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 26862306a36Sopenharmony_ci goto ufs2; 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, index); 27262306a36Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 27362306a36Sopenharmony_ci if (tmp) 27462306a36Sopenharmony_ci goto out; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci lastfrag = ufsi->i_lastfrag; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* will that be a new tail? */ 27962306a36Sopenharmony_ci if (new_fragment < UFS_NDIR_FRAGMENT && new_fragment >= lastfrag) 28062306a36Sopenharmony_ci nfrags = (new_fragment & uspi->s_fpbmask) + 1; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci goal = 0; 28362306a36Sopenharmony_ci if (index) { 28462306a36Sopenharmony_ci goal = ufs_data_ptr_to_cpu(sb, 28562306a36Sopenharmony_ci ufs_get_direct_data_ptr(uspi, ufsi, index - 1)); 28662306a36Sopenharmony_ci if (goal) 28762306a36Sopenharmony_ci goal += uspi->s_fpb; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), 29062306a36Sopenharmony_ci goal, nfrags, err, locked_page); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (!tmp) { 29362306a36Sopenharmony_ci *err = -ENOSPC; 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (new) 29862306a36Sopenharmony_ci *new = 1; 29962306a36Sopenharmony_ci inode_set_ctime_current(inode); 30062306a36Sopenharmony_ci if (IS_SYNC(inode)) 30162306a36Sopenharmony_ci ufs_sync_inode (inode); 30262306a36Sopenharmony_ci mark_inode_dirty(inode); 30362306a36Sopenharmony_ciout: 30462306a36Sopenharmony_ci return tmp + uspi->s_sbbase; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* This part : To be implemented .... 30762306a36Sopenharmony_ci Required only for writing, not required for READ-ONLY. 30862306a36Sopenharmony_ciufs2: 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci u2_block = ufs_fragstoblks(fragment); 31162306a36Sopenharmony_ci u2_blockoff = ufs_fragnum(fragment); 31262306a36Sopenharmony_ci p = ufsi->i_u1.u2_i_data + block; 31362306a36Sopenharmony_ci goal = 0; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cirepeat2: 31662306a36Sopenharmony_ci tmp = fs32_to_cpu(sb, *p); 31762306a36Sopenharmony_ci lastfrag = ufsi->i_lastfrag; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/** 32362306a36Sopenharmony_ci * ufs_inode_getblock() - allocate new block 32462306a36Sopenharmony_ci * @inode: pointer to inode 32562306a36Sopenharmony_ci * @ind_block: block number of the indirect block 32662306a36Sopenharmony_ci * @index: number of pointer within the indirect block 32762306a36Sopenharmony_ci * @new_fragment: number of new allocated fragment 32862306a36Sopenharmony_ci * (block will hold this fragment and also uspi->s_fpb-1) 32962306a36Sopenharmony_ci * @err: see ufs_inode_getfrag() 33062306a36Sopenharmony_ci * @new: see ufs_inode_getfrag() 33162306a36Sopenharmony_ci * @locked_page: see ufs_inode_getfrag() 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_cistatic u64 33462306a36Sopenharmony_ciufs_inode_getblock(struct inode *inode, u64 ind_block, 33562306a36Sopenharmony_ci unsigned index, sector_t new_fragment, int *err, 33662306a36Sopenharmony_ci int *new, struct page *locked_page) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 33962306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 34062306a36Sopenharmony_ci int shift = uspi->s_apbshift - uspi->s_fpbshift; 34162306a36Sopenharmony_ci u64 tmp = 0, goal; 34262306a36Sopenharmony_ci struct buffer_head *bh; 34362306a36Sopenharmony_ci void *p; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (!ind_block) 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci bh = sb_bread(sb, ind_block + (index >> shift)); 34962306a36Sopenharmony_ci if (unlikely(!bh)) { 35062306a36Sopenharmony_ci *err = -EIO; 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci index &= uspi->s_apbmask >> uspi->s_fpbshift; 35562306a36Sopenharmony_ci if (uspi->fs_magic == UFS2_MAGIC) 35662306a36Sopenharmony_ci p = (__fs64 *)bh->b_data + index; 35762306a36Sopenharmony_ci else 35862306a36Sopenharmony_ci p = (__fs32 *)bh->b_data + index; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 36162306a36Sopenharmony_ci if (tmp) 36262306a36Sopenharmony_ci goto out; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (index && (uspi->fs_magic == UFS2_MAGIC ? 36562306a36Sopenharmony_ci (tmp = fs64_to_cpu(sb, ((__fs64 *)bh->b_data)[index-1])) : 36662306a36Sopenharmony_ci (tmp = fs32_to_cpu(sb, ((__fs32 *)bh->b_data)[index-1])))) 36762306a36Sopenharmony_ci goal = tmp + uspi->s_fpb; 36862306a36Sopenharmony_ci else 36962306a36Sopenharmony_ci goal = bh->b_blocknr + uspi->s_fpb; 37062306a36Sopenharmony_ci tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, 37162306a36Sopenharmony_ci uspi->s_fpb, err, locked_page); 37262306a36Sopenharmony_ci if (!tmp) 37362306a36Sopenharmony_ci goto out; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (new) 37662306a36Sopenharmony_ci *new = 1; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci mark_buffer_dirty(bh); 37962306a36Sopenharmony_ci if (IS_SYNC(inode)) 38062306a36Sopenharmony_ci sync_dirty_buffer(bh); 38162306a36Sopenharmony_ci inode_set_ctime_current(inode); 38262306a36Sopenharmony_ci mark_inode_dirty(inode); 38362306a36Sopenharmony_ciout: 38462306a36Sopenharmony_ci brelse (bh); 38562306a36Sopenharmony_ci UFSD("EXIT\n"); 38662306a36Sopenharmony_ci if (tmp) 38762306a36Sopenharmony_ci tmp += uspi->s_sbbase; 38862306a36Sopenharmony_ci return tmp; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci/** 39262306a36Sopenharmony_ci * ufs_getfrag_block() - `get_block_t' function, interface between UFS and 39362306a36Sopenharmony_ci * read_folio, writepage and so on 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 39962306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 40062306a36Sopenharmony_ci int err = 0, new = 0; 40162306a36Sopenharmony_ci unsigned offsets[4]; 40262306a36Sopenharmony_ci int depth = ufs_block_to_path(inode, fragment >> uspi->s_fpbshift, offsets); 40362306a36Sopenharmony_ci u64 phys64 = 0; 40462306a36Sopenharmony_ci unsigned frag = fragment & uspi->s_fpbmask; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci phys64 = ufs_frag_map(inode, offsets, depth); 40762306a36Sopenharmony_ci if (!create) 40862306a36Sopenharmony_ci goto done; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (phys64) { 41162306a36Sopenharmony_ci if (fragment >= UFS_NDIR_FRAGMENT) 41262306a36Sopenharmony_ci goto done; 41362306a36Sopenharmony_ci read_seqlock_excl(&UFS_I(inode)->meta_lock); 41462306a36Sopenharmony_ci if (fragment < UFS_I(inode)->i_lastfrag) { 41562306a36Sopenharmony_ci read_sequnlock_excl(&UFS_I(inode)->meta_lock); 41662306a36Sopenharmony_ci goto done; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci read_sequnlock_excl(&UFS_I(inode)->meta_lock); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci /* This code entered only while writing ....? */ 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci mutex_lock(&UFS_I(inode)->truncate_mutex); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); 42562306a36Sopenharmony_ci if (unlikely(!depth)) { 42662306a36Sopenharmony_ci ufs_warning(sb, "ufs_get_block", "block > big"); 42762306a36Sopenharmony_ci err = -EIO; 42862306a36Sopenharmony_ci goto out; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (UFS_I(inode)->i_lastfrag < UFS_NDIR_FRAGMENT) { 43262306a36Sopenharmony_ci unsigned lastfrag = UFS_I(inode)->i_lastfrag; 43362306a36Sopenharmony_ci unsigned tailfrags = lastfrag & uspi->s_fpbmask; 43462306a36Sopenharmony_ci if (tailfrags && fragment >= lastfrag) { 43562306a36Sopenharmony_ci if (!ufs_extend_tail(inode, fragment, 43662306a36Sopenharmony_ci &err, bh_result->b_page)) 43762306a36Sopenharmony_ci goto out; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (depth == 1) { 44262306a36Sopenharmony_ci phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, 44362306a36Sopenharmony_ci &err, &new, bh_result->b_page); 44462306a36Sopenharmony_ci } else { 44562306a36Sopenharmony_ci int i; 44662306a36Sopenharmony_ci phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, 44762306a36Sopenharmony_ci &err, NULL, NULL); 44862306a36Sopenharmony_ci for (i = 1; i < depth - 1; i++) 44962306a36Sopenharmony_ci phys64 = ufs_inode_getblock(inode, phys64, offsets[i], 45062306a36Sopenharmony_ci fragment, &err, NULL, NULL); 45162306a36Sopenharmony_ci phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1], 45262306a36Sopenharmony_ci fragment, &err, &new, bh_result->b_page); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ciout: 45562306a36Sopenharmony_ci if (phys64) { 45662306a36Sopenharmony_ci phys64 += frag; 45762306a36Sopenharmony_ci map_bh(bh_result, sb, phys64); 45862306a36Sopenharmony_ci if (new) 45962306a36Sopenharmony_ci set_buffer_new(bh_result); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci mutex_unlock(&UFS_I(inode)->truncate_mutex); 46262306a36Sopenharmony_ci return err; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cidone: 46562306a36Sopenharmony_ci if (phys64) 46662306a36Sopenharmony_ci map_bh(bh_result, sb, phys64 + frag); 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int ufs_writepage(struct page *page, struct writeback_control *wbc) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci return block_write_full_page(page,ufs_getfrag_block,wbc); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic int ufs_read_folio(struct file *file, struct folio *folio) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci return block_read_full_folio(folio, ufs_getfrag_block); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ciint ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci return __block_write_begin(page, pos, len, ufs_getfrag_block); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic void ufs_truncate_blocks(struct inode *); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void ufs_write_failed(struct address_space *mapping, loff_t to) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct inode *inode = mapping->host; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (to > inode->i_size) { 49262306a36Sopenharmony_ci truncate_pagecache(inode, inode->i_size); 49362306a36Sopenharmony_ci ufs_truncate_blocks(inode); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int ufs_write_begin(struct file *file, struct address_space *mapping, 49862306a36Sopenharmony_ci loff_t pos, unsigned len, 49962306a36Sopenharmony_ci struct page **pagep, void **fsdata) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci int ret; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci ret = block_write_begin(mapping, pos, len, pagep, ufs_getfrag_block); 50462306a36Sopenharmony_ci if (unlikely(ret)) 50562306a36Sopenharmony_ci ufs_write_failed(mapping, pos + len); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return ret; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic int ufs_write_end(struct file *file, struct address_space *mapping, 51162306a36Sopenharmony_ci loff_t pos, unsigned len, unsigned copied, 51262306a36Sopenharmony_ci struct page *page, void *fsdata) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci int ret; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); 51762306a36Sopenharmony_ci if (ret < len) 51862306a36Sopenharmony_ci ufs_write_failed(mapping, pos + len); 51962306a36Sopenharmony_ci return ret; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic sector_t ufs_bmap(struct address_space *mapping, sector_t block) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci return generic_block_bmap(mapping,block,ufs_getfrag_block); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ciconst struct address_space_operations ufs_aops = { 52862306a36Sopenharmony_ci .dirty_folio = block_dirty_folio, 52962306a36Sopenharmony_ci .invalidate_folio = block_invalidate_folio, 53062306a36Sopenharmony_ci .read_folio = ufs_read_folio, 53162306a36Sopenharmony_ci .writepage = ufs_writepage, 53262306a36Sopenharmony_ci .write_begin = ufs_write_begin, 53362306a36Sopenharmony_ci .write_end = ufs_write_end, 53462306a36Sopenharmony_ci .bmap = ufs_bmap 53562306a36Sopenharmony_ci}; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic void ufs_set_inode_ops(struct inode *inode) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 54062306a36Sopenharmony_ci inode->i_op = &ufs_file_inode_operations; 54162306a36Sopenharmony_ci inode->i_fop = &ufs_file_operations; 54262306a36Sopenharmony_ci inode->i_mapping->a_ops = &ufs_aops; 54362306a36Sopenharmony_ci } else if (S_ISDIR(inode->i_mode)) { 54462306a36Sopenharmony_ci inode->i_op = &ufs_dir_inode_operations; 54562306a36Sopenharmony_ci inode->i_fop = &ufs_dir_operations; 54662306a36Sopenharmony_ci inode->i_mapping->a_ops = &ufs_aops; 54762306a36Sopenharmony_ci } else if (S_ISLNK(inode->i_mode)) { 54862306a36Sopenharmony_ci if (!inode->i_blocks) { 54962306a36Sopenharmony_ci inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink; 55062306a36Sopenharmony_ci inode->i_op = &simple_symlink_inode_operations; 55162306a36Sopenharmony_ci } else { 55262306a36Sopenharmony_ci inode->i_mapping->a_ops = &ufs_aops; 55362306a36Sopenharmony_ci inode->i_op = &page_symlink_inode_operations; 55462306a36Sopenharmony_ci inode_nohighmem(inode); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci } else 55762306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, 55862306a36Sopenharmony_ci ufs_get_inode_dev(inode->i_sb, UFS_I(inode))); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 56462306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 56562306a36Sopenharmony_ci umode_t mode; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* 56862306a36Sopenharmony_ci * Copy data to the in-core inode. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci inode->i_mode = mode = fs16_to_cpu(sb, ufs_inode->ui_mode); 57162306a36Sopenharmony_ci set_nlink(inode, fs16_to_cpu(sb, ufs_inode->ui_nlink)); 57262306a36Sopenharmony_ci if (inode->i_nlink == 0) 57362306a36Sopenharmony_ci return -ESTALE; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* 57662306a36Sopenharmony_ci * Linux now has 32-bit uid and gid, so we can support EFT. 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_ci i_uid_write(inode, ufs_get_inode_uid(sb, ufs_inode)); 57962306a36Sopenharmony_ci i_gid_write(inode, ufs_get_inode_gid(sb, ufs_inode)); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci inode->i_size = fs64_to_cpu(sb, ufs_inode->ui_size); 58262306a36Sopenharmony_ci inode->i_atime.tv_sec = (signed)fs32_to_cpu(sb, ufs_inode->ui_atime.tv_sec); 58362306a36Sopenharmony_ci inode_set_ctime(inode, 58462306a36Sopenharmony_ci (signed)fs32_to_cpu(sb, ufs_inode->ui_ctime.tv_sec), 58562306a36Sopenharmony_ci 0); 58662306a36Sopenharmony_ci inode->i_mtime.tv_sec = (signed)fs32_to_cpu(sb, ufs_inode->ui_mtime.tv_sec); 58762306a36Sopenharmony_ci inode->i_mtime.tv_nsec = 0; 58862306a36Sopenharmony_ci inode->i_atime.tv_nsec = 0; 58962306a36Sopenharmony_ci inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks); 59062306a36Sopenharmony_ci inode->i_generation = fs32_to_cpu(sb, ufs_inode->ui_gen); 59162306a36Sopenharmony_ci ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags); 59262306a36Sopenharmony_ci ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); 59362306a36Sopenharmony_ci ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { 59762306a36Sopenharmony_ci memcpy(ufsi->i_u1.i_data, &ufs_inode->ui_u2.ui_addr, 59862306a36Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_addr)); 59962306a36Sopenharmony_ci } else { 60062306a36Sopenharmony_ci memcpy(ufsi->i_u1.i_symlink, ufs_inode->ui_u2.ui_symlink, 60162306a36Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_symlink) - 1); 60262306a36Sopenharmony_ci ufsi->i_u1.i_symlink[sizeof(ufs_inode->ui_u2.ui_symlink) - 1] = 0; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci return 0; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 61062306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 61162306a36Sopenharmony_ci umode_t mode; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino); 61462306a36Sopenharmony_ci /* 61562306a36Sopenharmony_ci * Copy data to the in-core inode. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode); 61862306a36Sopenharmony_ci set_nlink(inode, fs16_to_cpu(sb, ufs2_inode->ui_nlink)); 61962306a36Sopenharmony_ci if (inode->i_nlink == 0) 62062306a36Sopenharmony_ci return -ESTALE; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* 62362306a36Sopenharmony_ci * Linux now has 32-bit uid and gid, so we can support EFT. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci i_uid_write(inode, fs32_to_cpu(sb, ufs2_inode->ui_uid)); 62662306a36Sopenharmony_ci i_gid_write(inode, fs32_to_cpu(sb, ufs2_inode->ui_gid)); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size); 62962306a36Sopenharmony_ci inode->i_atime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_atime); 63062306a36Sopenharmony_ci inode_set_ctime(inode, fs64_to_cpu(sb, ufs2_inode->ui_ctime), 63162306a36Sopenharmony_ci fs32_to_cpu(sb, ufs2_inode->ui_ctimensec)); 63262306a36Sopenharmony_ci inode->i_mtime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_mtime); 63362306a36Sopenharmony_ci inode->i_atime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_atimensec); 63462306a36Sopenharmony_ci inode->i_mtime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_mtimensec); 63562306a36Sopenharmony_ci inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks); 63662306a36Sopenharmony_ci inode->i_generation = fs32_to_cpu(sb, ufs2_inode->ui_gen); 63762306a36Sopenharmony_ci ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags); 63862306a36Sopenharmony_ci /* 63962306a36Sopenharmony_ci ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); 64062306a36Sopenharmony_ci ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { 64462306a36Sopenharmony_ci memcpy(ufsi->i_u1.u2_i_data, &ufs2_inode->ui_u2.ui_addr, 64562306a36Sopenharmony_ci sizeof(ufs2_inode->ui_u2.ui_addr)); 64662306a36Sopenharmony_ci } else { 64762306a36Sopenharmony_ci memcpy(ufsi->i_u1.i_symlink, ufs2_inode->ui_u2.ui_symlink, 64862306a36Sopenharmony_ci sizeof(ufs2_inode->ui_u2.ui_symlink) - 1); 64962306a36Sopenharmony_ci ufsi->i_u1.i_symlink[sizeof(ufs2_inode->ui_u2.ui_symlink) - 1] = 0; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci return 0; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistruct inode *ufs_iget(struct super_block *sb, unsigned long ino) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct ufs_inode_info *ufsi; 65762306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 65862306a36Sopenharmony_ci struct buffer_head * bh; 65962306a36Sopenharmony_ci struct inode *inode; 66062306a36Sopenharmony_ci int err = -EIO; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci UFSD("ENTER, ino %lu\n", ino); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (ino < UFS_ROOTINO || ino > (uspi->s_ncg * uspi->s_ipg)) { 66562306a36Sopenharmony_ci ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n", 66662306a36Sopenharmony_ci ino); 66762306a36Sopenharmony_ci return ERR_PTR(-EIO); 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci inode = iget_locked(sb, ino); 67162306a36Sopenharmony_ci if (!inode) 67262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 67362306a36Sopenharmony_ci if (!(inode->i_state & I_NEW)) 67462306a36Sopenharmony_ci return inode; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci ufsi = UFS_I(inode); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino)); 67962306a36Sopenharmony_ci if (!bh) { 68062306a36Sopenharmony_ci ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n", 68162306a36Sopenharmony_ci inode->i_ino); 68262306a36Sopenharmony_ci goto bad_inode; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci if ((UFS_SB(sb)->s_flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { 68562306a36Sopenharmony_ci struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci err = ufs2_read_inode(inode, 68862306a36Sopenharmony_ci ufs2_inode + ufs_inotofsbo(inode->i_ino)); 68962306a36Sopenharmony_ci } else { 69062306a36Sopenharmony_ci struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci err = ufs1_read_inode(inode, 69362306a36Sopenharmony_ci ufs_inode + ufs_inotofsbo(inode->i_ino)); 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci brelse(bh); 69662306a36Sopenharmony_ci if (err) 69762306a36Sopenharmony_ci goto bad_inode; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci inode_inc_iversion(inode); 70062306a36Sopenharmony_ci ufsi->i_lastfrag = 70162306a36Sopenharmony_ci (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift; 70262306a36Sopenharmony_ci ufsi->i_dir_start_lookup = 0; 70362306a36Sopenharmony_ci ufsi->i_osync = 0; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci ufs_set_inode_ops(inode); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci UFSD("EXIT\n"); 70862306a36Sopenharmony_ci unlock_new_inode(inode); 70962306a36Sopenharmony_ci return inode; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cibad_inode: 71262306a36Sopenharmony_ci iget_failed(inode); 71362306a36Sopenharmony_ci return ERR_PTR(err); 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 71962306a36Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); 72262306a36Sopenharmony_ci ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci ufs_set_inode_uid(sb, ufs_inode, i_uid_read(inode)); 72562306a36Sopenharmony_ci ufs_set_inode_gid(sb, ufs_inode, i_gid_read(inode)); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); 72862306a36Sopenharmony_ci ufs_inode->ui_atime.tv_sec = cpu_to_fs32(sb, inode->i_atime.tv_sec); 72962306a36Sopenharmony_ci ufs_inode->ui_atime.tv_usec = 0; 73062306a36Sopenharmony_ci ufs_inode->ui_ctime.tv_sec = cpu_to_fs32(sb, 73162306a36Sopenharmony_ci inode_get_ctime(inode).tv_sec); 73262306a36Sopenharmony_ci ufs_inode->ui_ctime.tv_usec = 0; 73362306a36Sopenharmony_ci ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, inode->i_mtime.tv_sec); 73462306a36Sopenharmony_ci ufs_inode->ui_mtime.tv_usec = 0; 73562306a36Sopenharmony_ci ufs_inode->ui_blocks = cpu_to_fs32(sb, inode->i_blocks); 73662306a36Sopenharmony_ci ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); 73762306a36Sopenharmony_ci ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if ((UFS_SB(sb)->s_flags & UFS_UID_MASK) == UFS_UID_EFT) { 74062306a36Sopenharmony_ci ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, ufsi->i_shadow); 74162306a36Sopenharmony_ci ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, ufsi->i_oeftflag); 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { 74562306a36Sopenharmony_ci /* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ 74662306a36Sopenharmony_ci ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.i_data[0]; 74762306a36Sopenharmony_ci } else if (inode->i_blocks) { 74862306a36Sopenharmony_ci memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.i_data, 74962306a36Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_addr)); 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci else { 75262306a36Sopenharmony_ci memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink, 75362306a36Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_symlink)); 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (!inode->i_nlink) 75762306a36Sopenharmony_ci memset (ufs_inode, 0, sizeof(struct ufs_inode)); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic void ufs2_update_inode(struct inode *inode, struct ufs2_inode *ufs_inode) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 76362306a36Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci UFSD("ENTER\n"); 76662306a36Sopenharmony_ci ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); 76762306a36Sopenharmony_ci ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci ufs_inode->ui_uid = cpu_to_fs32(sb, i_uid_read(inode)); 77062306a36Sopenharmony_ci ufs_inode->ui_gid = cpu_to_fs32(sb, i_gid_read(inode)); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); 77362306a36Sopenharmony_ci ufs_inode->ui_atime = cpu_to_fs64(sb, inode->i_atime.tv_sec); 77462306a36Sopenharmony_ci ufs_inode->ui_atimensec = cpu_to_fs32(sb, inode->i_atime.tv_nsec); 77562306a36Sopenharmony_ci ufs_inode->ui_ctime = cpu_to_fs64(sb, inode_get_ctime(inode).tv_sec); 77662306a36Sopenharmony_ci ufs_inode->ui_ctimensec = cpu_to_fs32(sb, 77762306a36Sopenharmony_ci inode_get_ctime(inode).tv_nsec); 77862306a36Sopenharmony_ci ufs_inode->ui_mtime = cpu_to_fs64(sb, inode->i_mtime.tv_sec); 77962306a36Sopenharmony_ci ufs_inode->ui_mtimensec = cpu_to_fs32(sb, inode->i_mtime.tv_nsec); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci ufs_inode->ui_blocks = cpu_to_fs64(sb, inode->i_blocks); 78262306a36Sopenharmony_ci ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); 78362306a36Sopenharmony_ci ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { 78662306a36Sopenharmony_ci /* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ 78762306a36Sopenharmony_ci ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.u2_i_data[0]; 78862306a36Sopenharmony_ci } else if (inode->i_blocks) { 78962306a36Sopenharmony_ci memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.u2_i_data, 79062306a36Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_addr)); 79162306a36Sopenharmony_ci } else { 79262306a36Sopenharmony_ci memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink, 79362306a36Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_symlink)); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (!inode->i_nlink) 79762306a36Sopenharmony_ci memset (ufs_inode, 0, sizeof(struct ufs2_inode)); 79862306a36Sopenharmony_ci UFSD("EXIT\n"); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic int ufs_update_inode(struct inode * inode, int do_sync) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 80462306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 80562306a36Sopenharmony_ci struct buffer_head * bh; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci UFSD("ENTER, ino %lu\n", inode->i_ino); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (inode->i_ino < UFS_ROOTINO || 81062306a36Sopenharmony_ci inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { 81162306a36Sopenharmony_ci ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); 81262306a36Sopenharmony_ci return -1; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci bh = sb_bread(sb, ufs_inotofsba(inode->i_ino)); 81662306a36Sopenharmony_ci if (!bh) { 81762306a36Sopenharmony_ci ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); 81862306a36Sopenharmony_ci return -1; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci if (uspi->fs_magic == UFS2_MAGIC) { 82162306a36Sopenharmony_ci struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci ufs2_update_inode(inode, 82462306a36Sopenharmony_ci ufs2_inode + ufs_inotofsbo(inode->i_ino)); 82562306a36Sopenharmony_ci } else { 82662306a36Sopenharmony_ci struct ufs_inode *ufs_inode = (struct ufs_inode *) bh->b_data; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci ufs1_update_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino)); 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci mark_buffer_dirty(bh); 83262306a36Sopenharmony_ci if (do_sync) 83362306a36Sopenharmony_ci sync_dirty_buffer(bh); 83462306a36Sopenharmony_ci brelse (bh); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci UFSD("EXIT\n"); 83762306a36Sopenharmony_ci return 0; 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ciint ufs_write_inode(struct inode *inode, struct writeback_control *wbc) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci return ufs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL); 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ciint ufs_sync_inode (struct inode *inode) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci return ufs_update_inode (inode, 1); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_civoid ufs_evict_inode(struct inode * inode) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci int want_delete = 0; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (!inode->i_nlink && !is_bad_inode(inode)) 85562306a36Sopenharmony_ci want_delete = 1; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 85862306a36Sopenharmony_ci if (want_delete) { 85962306a36Sopenharmony_ci inode->i_size = 0; 86062306a36Sopenharmony_ci if (inode->i_blocks && 86162306a36Sopenharmony_ci (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || 86262306a36Sopenharmony_ci S_ISLNK(inode->i_mode))) 86362306a36Sopenharmony_ci ufs_truncate_blocks(inode); 86462306a36Sopenharmony_ci ufs_update_inode(inode, inode_needs_sync(inode)); 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci invalidate_inode_buffers(inode); 86862306a36Sopenharmony_ci clear_inode(inode); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (want_delete) 87162306a36Sopenharmony_ci ufs_free_inode(inode); 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cistruct to_free { 87562306a36Sopenharmony_ci struct inode *inode; 87662306a36Sopenharmony_ci u64 to; 87762306a36Sopenharmony_ci unsigned count; 87862306a36Sopenharmony_ci}; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic inline void free_data(struct to_free *ctx, u64 from, unsigned count) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci if (ctx->count && ctx->to != from) { 88362306a36Sopenharmony_ci ufs_free_blocks(ctx->inode, ctx->to - ctx->count, ctx->count); 88462306a36Sopenharmony_ci ctx->count = 0; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci ctx->count += count; 88762306a36Sopenharmony_ci ctx->to = from + count; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic void ufs_trunc_direct(struct inode *inode) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 89562306a36Sopenharmony_ci struct super_block * sb; 89662306a36Sopenharmony_ci struct ufs_sb_private_info * uspi; 89762306a36Sopenharmony_ci void *p; 89862306a36Sopenharmony_ci u64 frag1, frag2, frag3, frag4, block1, block2; 89962306a36Sopenharmony_ci struct to_free ctx = {.inode = inode}; 90062306a36Sopenharmony_ci unsigned i, tmp; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci UFSD("ENTER: ino %lu\n", inode->i_ino); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci sb = inode->i_sb; 90562306a36Sopenharmony_ci uspi = UFS_SB(sb)->s_uspi; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci frag1 = DIRECT_FRAGMENT; 90862306a36Sopenharmony_ci frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); 90962306a36Sopenharmony_ci frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); 91062306a36Sopenharmony_ci frag3 = frag4 & ~uspi->s_fpbmask; 91162306a36Sopenharmony_ci block1 = block2 = 0; 91262306a36Sopenharmony_ci if (frag2 > frag3) { 91362306a36Sopenharmony_ci frag2 = frag4; 91462306a36Sopenharmony_ci frag3 = frag4 = 0; 91562306a36Sopenharmony_ci } else if (frag2 < frag3) { 91662306a36Sopenharmony_ci block1 = ufs_fragstoblks (frag2); 91762306a36Sopenharmony_ci block2 = ufs_fragstoblks (frag3); 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu," 92162306a36Sopenharmony_ci " frag3 %llu, frag4 %llu\n", inode->i_ino, 92262306a36Sopenharmony_ci (unsigned long long)frag1, (unsigned long long)frag2, 92362306a36Sopenharmony_ci (unsigned long long)block1, (unsigned long long)block2, 92462306a36Sopenharmony_ci (unsigned long long)frag3, (unsigned long long)frag4); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (frag1 >= frag2) 92762306a36Sopenharmony_ci goto next1; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* 93062306a36Sopenharmony_ci * Free first free fragments 93162306a36Sopenharmony_ci */ 93262306a36Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1)); 93362306a36Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 93462306a36Sopenharmony_ci if (!tmp ) 93562306a36Sopenharmony_ci ufs_panic (sb, "ufs_trunc_direct", "internal error"); 93662306a36Sopenharmony_ci frag2 -= frag1; 93762306a36Sopenharmony_ci frag1 = ufs_fragnum (frag1); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci ufs_free_fragments(inode, tmp + frag1, frag2); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cinext1: 94262306a36Sopenharmony_ci /* 94362306a36Sopenharmony_ci * Free whole blocks 94462306a36Sopenharmony_ci */ 94562306a36Sopenharmony_ci for (i = block1 ; i < block2; i++) { 94662306a36Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, i); 94762306a36Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 94862306a36Sopenharmony_ci if (!tmp) 94962306a36Sopenharmony_ci continue; 95062306a36Sopenharmony_ci write_seqlock(&ufsi->meta_lock); 95162306a36Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 95262306a36Sopenharmony_ci write_sequnlock(&ufsi->meta_lock); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci free_data(&ctx, tmp, uspi->s_fpb); 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci free_data(&ctx, 0, 0); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (frag3 >= frag4) 96062306a36Sopenharmony_ci goto next3; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* 96362306a36Sopenharmony_ci * Free last free fragments 96462306a36Sopenharmony_ci */ 96562306a36Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3)); 96662306a36Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 96762306a36Sopenharmony_ci if (!tmp ) 96862306a36Sopenharmony_ci ufs_panic(sb, "ufs_truncate_direct", "internal error"); 96962306a36Sopenharmony_ci frag4 = ufs_fragnum (frag4); 97062306a36Sopenharmony_ci write_seqlock(&ufsi->meta_lock); 97162306a36Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 97262306a36Sopenharmony_ci write_sequnlock(&ufsi->meta_lock); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci ufs_free_fragments (inode, tmp, frag4); 97562306a36Sopenharmony_ci next3: 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci UFSD("EXIT: ino %lu\n", inode->i_ino); 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic void free_full_branch(struct inode *inode, u64 ind_block, int depth) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 98362306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 98462306a36Sopenharmony_ci struct ufs_buffer_head *ubh = ubh_bread(sb, ind_block, uspi->s_bsize); 98562306a36Sopenharmony_ci unsigned i; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (!ubh) 98862306a36Sopenharmony_ci return; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (--depth) { 99162306a36Sopenharmony_ci for (i = 0; i < uspi->s_apb; i++) { 99262306a36Sopenharmony_ci void *p = ubh_get_data_ptr(uspi, ubh, i); 99362306a36Sopenharmony_ci u64 block = ufs_data_ptr_to_cpu(sb, p); 99462306a36Sopenharmony_ci if (block) 99562306a36Sopenharmony_ci free_full_branch(inode, block, depth); 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci } else { 99862306a36Sopenharmony_ci struct to_free ctx = {.inode = inode}; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci for (i = 0; i < uspi->s_apb; i++) { 100162306a36Sopenharmony_ci void *p = ubh_get_data_ptr(uspi, ubh, i); 100262306a36Sopenharmony_ci u64 block = ufs_data_ptr_to_cpu(sb, p); 100362306a36Sopenharmony_ci if (block) 100462306a36Sopenharmony_ci free_data(&ctx, block, uspi->s_fpb); 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci free_data(&ctx, 0, 0); 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci ubh_bforget(ubh); 101062306a36Sopenharmony_ci ufs_free_blocks(inode, ind_block, uspi->s_fpb); 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic void free_branch_tail(struct inode *inode, unsigned from, struct ufs_buffer_head *ubh, int depth) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 101662306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 101762306a36Sopenharmony_ci unsigned i; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (--depth) { 102062306a36Sopenharmony_ci for (i = from; i < uspi->s_apb ; i++) { 102162306a36Sopenharmony_ci void *p = ubh_get_data_ptr(uspi, ubh, i); 102262306a36Sopenharmony_ci u64 block = ufs_data_ptr_to_cpu(sb, p); 102362306a36Sopenharmony_ci if (block) { 102462306a36Sopenharmony_ci write_seqlock(&UFS_I(inode)->meta_lock); 102562306a36Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 102662306a36Sopenharmony_ci write_sequnlock(&UFS_I(inode)->meta_lock); 102762306a36Sopenharmony_ci ubh_mark_buffer_dirty(ubh); 102862306a36Sopenharmony_ci free_full_branch(inode, block, depth); 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci } else { 103262306a36Sopenharmony_ci struct to_free ctx = {.inode = inode}; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci for (i = from; i < uspi->s_apb; i++) { 103562306a36Sopenharmony_ci void *p = ubh_get_data_ptr(uspi, ubh, i); 103662306a36Sopenharmony_ci u64 block = ufs_data_ptr_to_cpu(sb, p); 103762306a36Sopenharmony_ci if (block) { 103862306a36Sopenharmony_ci write_seqlock(&UFS_I(inode)->meta_lock); 103962306a36Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 104062306a36Sopenharmony_ci write_sequnlock(&UFS_I(inode)->meta_lock); 104162306a36Sopenharmony_ci ubh_mark_buffer_dirty(ubh); 104262306a36Sopenharmony_ci free_data(&ctx, block, uspi->s_fpb); 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci free_data(&ctx, 0, 0); 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci if (IS_SYNC(inode) && ubh_buffer_dirty(ubh)) 104862306a36Sopenharmony_ci ubh_sync_block(ubh); 104962306a36Sopenharmony_ci ubh_brelse(ubh); 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic int ufs_alloc_lastblock(struct inode *inode, loff_t size) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci int err = 0; 105562306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 105662306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 105762306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 105862306a36Sopenharmony_ci unsigned i, end; 105962306a36Sopenharmony_ci sector_t lastfrag; 106062306a36Sopenharmony_ci struct page *lastpage; 106162306a36Sopenharmony_ci struct buffer_head *bh; 106262306a36Sopenharmony_ci u64 phys64; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci lastfrag = (size + uspi->s_fsize - 1) >> uspi->s_fshift; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (!lastfrag) 106762306a36Sopenharmony_ci goto out; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci lastfrag--; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci lastpage = ufs_get_locked_page(mapping, lastfrag >> 107262306a36Sopenharmony_ci (PAGE_SHIFT - inode->i_blkbits)); 107362306a36Sopenharmony_ci if (IS_ERR(lastpage)) { 107462306a36Sopenharmony_ci err = -EIO; 107562306a36Sopenharmony_ci goto out; 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci end = lastfrag & ((1 << (PAGE_SHIFT - inode->i_blkbits)) - 1); 107962306a36Sopenharmony_ci bh = page_buffers(lastpage); 108062306a36Sopenharmony_ci for (i = 0; i < end; ++i) 108162306a36Sopenharmony_ci bh = bh->b_this_page; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci err = ufs_getfrag_block(inode, lastfrag, bh, 1); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (unlikely(err)) 108762306a36Sopenharmony_ci goto out_unlock; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (buffer_new(bh)) { 109062306a36Sopenharmony_ci clear_buffer_new(bh); 109162306a36Sopenharmony_ci clean_bdev_bh_alias(bh); 109262306a36Sopenharmony_ci /* 109362306a36Sopenharmony_ci * we do not zeroize fragment, because of 109462306a36Sopenharmony_ci * if it maped to hole, it already contains zeroes 109562306a36Sopenharmony_ci */ 109662306a36Sopenharmony_ci set_buffer_uptodate(bh); 109762306a36Sopenharmony_ci mark_buffer_dirty(bh); 109862306a36Sopenharmony_ci set_page_dirty(lastpage); 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (lastfrag >= UFS_IND_FRAGMENT) { 110262306a36Sopenharmony_ci end = uspi->s_fpb - ufs_fragnum(lastfrag) - 1; 110362306a36Sopenharmony_ci phys64 = bh->b_blocknr + 1; 110462306a36Sopenharmony_ci for (i = 0; i < end; ++i) { 110562306a36Sopenharmony_ci bh = sb_getblk(sb, i + phys64); 110662306a36Sopenharmony_ci lock_buffer(bh); 110762306a36Sopenharmony_ci memset(bh->b_data, 0, sb->s_blocksize); 110862306a36Sopenharmony_ci set_buffer_uptodate(bh); 110962306a36Sopenharmony_ci mark_buffer_dirty(bh); 111062306a36Sopenharmony_ci unlock_buffer(bh); 111162306a36Sopenharmony_ci sync_dirty_buffer(bh); 111262306a36Sopenharmony_ci brelse(bh); 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ciout_unlock: 111662306a36Sopenharmony_ci ufs_put_locked_page(lastpage); 111762306a36Sopenharmony_ciout: 111862306a36Sopenharmony_ci return err; 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_cistatic void ufs_truncate_blocks(struct inode *inode) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 112462306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 112562306a36Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 112662306a36Sopenharmony_ci unsigned offsets[4]; 112762306a36Sopenharmony_ci int depth; 112862306a36Sopenharmony_ci int depth2; 112962306a36Sopenharmony_ci unsigned i; 113062306a36Sopenharmony_ci struct ufs_buffer_head *ubh[3]; 113162306a36Sopenharmony_ci void *p; 113262306a36Sopenharmony_ci u64 block; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (inode->i_size) { 113562306a36Sopenharmony_ci sector_t last = (inode->i_size - 1) >> uspi->s_bshift; 113662306a36Sopenharmony_ci depth = ufs_block_to_path(inode, last, offsets); 113762306a36Sopenharmony_ci if (!depth) 113862306a36Sopenharmony_ci return; 113962306a36Sopenharmony_ci } else { 114062306a36Sopenharmony_ci depth = 1; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci for (depth2 = depth - 1; depth2; depth2--) 114462306a36Sopenharmony_ci if (offsets[depth2] != uspi->s_apb - 1) 114562306a36Sopenharmony_ci break; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci mutex_lock(&ufsi->truncate_mutex); 114862306a36Sopenharmony_ci if (depth == 1) { 114962306a36Sopenharmony_ci ufs_trunc_direct(inode); 115062306a36Sopenharmony_ci offsets[0] = UFS_IND_BLOCK; 115162306a36Sopenharmony_ci } else { 115262306a36Sopenharmony_ci /* get the blocks that should be partially emptied */ 115362306a36Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]++); 115462306a36Sopenharmony_ci for (i = 0; i < depth2; i++) { 115562306a36Sopenharmony_ci block = ufs_data_ptr_to_cpu(sb, p); 115662306a36Sopenharmony_ci if (!block) 115762306a36Sopenharmony_ci break; 115862306a36Sopenharmony_ci ubh[i] = ubh_bread(sb, block, uspi->s_bsize); 115962306a36Sopenharmony_ci if (!ubh[i]) { 116062306a36Sopenharmony_ci write_seqlock(&ufsi->meta_lock); 116162306a36Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 116262306a36Sopenharmony_ci write_sequnlock(&ufsi->meta_lock); 116362306a36Sopenharmony_ci break; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci p = ubh_get_data_ptr(uspi, ubh[i], offsets[i + 1]++); 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci while (i--) 116862306a36Sopenharmony_ci free_branch_tail(inode, offsets[i + 1], ubh[i], depth - i - 1); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) { 117162306a36Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, i); 117262306a36Sopenharmony_ci block = ufs_data_ptr_to_cpu(sb, p); 117362306a36Sopenharmony_ci if (block) { 117462306a36Sopenharmony_ci write_seqlock(&ufsi->meta_lock); 117562306a36Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 117662306a36Sopenharmony_ci write_sequnlock(&ufsi->meta_lock); 117762306a36Sopenharmony_ci free_full_branch(inode, block, i - UFS_IND_BLOCK + 1); 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci read_seqlock_excl(&ufsi->meta_lock); 118162306a36Sopenharmony_ci ufsi->i_lastfrag = DIRECT_FRAGMENT; 118262306a36Sopenharmony_ci read_sequnlock_excl(&ufsi->meta_lock); 118362306a36Sopenharmony_ci mark_inode_dirty(inode); 118462306a36Sopenharmony_ci mutex_unlock(&ufsi->truncate_mutex); 118562306a36Sopenharmony_ci} 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_cistatic int ufs_truncate(struct inode *inode, loff_t size) 118862306a36Sopenharmony_ci{ 118962306a36Sopenharmony_ci int err = 0; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", 119262306a36Sopenharmony_ci inode->i_ino, (unsigned long long)size, 119362306a36Sopenharmony_ci (unsigned long long)i_size_read(inode)); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || 119662306a36Sopenharmony_ci S_ISLNK(inode->i_mode))) 119762306a36Sopenharmony_ci return -EINVAL; 119862306a36Sopenharmony_ci if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) 119962306a36Sopenharmony_ci return -EPERM; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci err = ufs_alloc_lastblock(inode, size); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (err) 120462306a36Sopenharmony_ci goto out; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci block_truncate_page(inode->i_mapping, size, ufs_getfrag_block); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci truncate_setsize(inode, size); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci ufs_truncate_blocks(inode); 121162306a36Sopenharmony_ci inode->i_mtime = inode_set_ctime_current(inode); 121262306a36Sopenharmony_ci mark_inode_dirty(inode); 121362306a36Sopenharmony_ciout: 121462306a36Sopenharmony_ci UFSD("EXIT: err %d\n", err); 121562306a36Sopenharmony_ci return err; 121662306a36Sopenharmony_ci} 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ciint ufs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 121962306a36Sopenharmony_ci struct iattr *attr) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 122262306a36Sopenharmony_ci unsigned int ia_valid = attr->ia_valid; 122362306a36Sopenharmony_ci int error; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci error = setattr_prepare(&nop_mnt_idmap, dentry, attr); 122662306a36Sopenharmony_ci if (error) 122762306a36Sopenharmony_ci return error; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) { 123062306a36Sopenharmony_ci error = ufs_truncate(inode, attr->ia_size); 123162306a36Sopenharmony_ci if (error) 123262306a36Sopenharmony_ci return error; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci setattr_copy(&nop_mnt_idmap, inode, attr); 123662306a36Sopenharmony_ci mark_inode_dirty(inode); 123762306a36Sopenharmony_ci return 0; 123862306a36Sopenharmony_ci} 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ciconst struct inode_operations ufs_file_inode_operations = { 124162306a36Sopenharmony_ci .setattr = ufs_setattr, 124262306a36Sopenharmony_ci}; 1243