18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/ufs/inode.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1998 68c2ecf20Sopenharmony_ci * Daniel Pirkl <daniel.pirkl@email.cz> 78c2ecf20Sopenharmony_ci * Charles University, Faculty of Mathematics and Physics 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * from 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * linux/fs/ext2/inode.c 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 148c2ecf20Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 158c2ecf20Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal 168c2ecf20Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI) 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * from 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * linux/fs/minix/inode.c 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 258c2ecf20Sopenharmony_ci * Big-endian to little-endian byte-swapping/bitmaps by 268c2ecf20Sopenharmony_ci * David S. Miller (davem@caip.rutgers.edu), 1995 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/errno.h> 328c2ecf20Sopenharmony_ci#include <linux/fs.h> 338c2ecf20Sopenharmony_ci#include <linux/time.h> 348c2ecf20Sopenharmony_ci#include <linux/stat.h> 358c2ecf20Sopenharmony_ci#include <linux/string.h> 368c2ecf20Sopenharmony_ci#include <linux/mm.h> 378c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 388c2ecf20Sopenharmony_ci#include <linux/writeback.h> 398c2ecf20Sopenharmony_ci#include <linux/iversion.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include "ufs_fs.h" 428c2ecf20Sopenharmony_ci#include "ufs.h" 438c2ecf20Sopenharmony_ci#include "swab.h" 448c2ecf20Sopenharmony_ci#include "util.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int ufs_block_to_path(struct inode *inode, sector_t i_block, unsigned offsets[4]) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; 498c2ecf20Sopenharmony_ci int ptrs = uspi->s_apb; 508c2ecf20Sopenharmony_ci int ptrs_bits = uspi->s_apbshift; 518c2ecf20Sopenharmony_ci const long direct_blocks = UFS_NDADDR, 528c2ecf20Sopenharmony_ci indirect_blocks = ptrs, 538c2ecf20Sopenharmony_ci double_blocks = (1 << (ptrs_bits * 2)); 548c2ecf20Sopenharmony_ci int n = 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); 588c2ecf20Sopenharmony_ci if (i_block < direct_blocks) { 598c2ecf20Sopenharmony_ci offsets[n++] = i_block; 608c2ecf20Sopenharmony_ci } else if ((i_block -= direct_blocks) < indirect_blocks) { 618c2ecf20Sopenharmony_ci offsets[n++] = UFS_IND_BLOCK; 628c2ecf20Sopenharmony_ci offsets[n++] = i_block; 638c2ecf20Sopenharmony_ci } else if ((i_block -= indirect_blocks) < double_blocks) { 648c2ecf20Sopenharmony_ci offsets[n++] = UFS_DIND_BLOCK; 658c2ecf20Sopenharmony_ci offsets[n++] = i_block >> ptrs_bits; 668c2ecf20Sopenharmony_ci offsets[n++] = i_block & (ptrs - 1); 678c2ecf20Sopenharmony_ci } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { 688c2ecf20Sopenharmony_ci offsets[n++] = UFS_TIND_BLOCK; 698c2ecf20Sopenharmony_ci offsets[n++] = i_block >> (ptrs_bits * 2); 708c2ecf20Sopenharmony_ci offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); 718c2ecf20Sopenharmony_ci offsets[n++] = i_block & (ptrs - 1); 728c2ecf20Sopenharmony_ci } else { 738c2ecf20Sopenharmony_ci ufs_warning(inode->i_sb, "ufs_block_to_path", "block > big"); 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci return n; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_citypedef struct { 798c2ecf20Sopenharmony_ci void *p; 808c2ecf20Sopenharmony_ci union { 818c2ecf20Sopenharmony_ci __fs32 key32; 828c2ecf20Sopenharmony_ci __fs64 key64; 838c2ecf20Sopenharmony_ci }; 848c2ecf20Sopenharmony_ci struct buffer_head *bh; 858c2ecf20Sopenharmony_ci} Indirect; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic inline int grow_chain32(struct ufs_inode_info *ufsi, 888c2ecf20Sopenharmony_ci struct buffer_head *bh, __fs32 *v, 898c2ecf20Sopenharmony_ci Indirect *from, Indirect *to) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci Indirect *p; 928c2ecf20Sopenharmony_ci unsigned seq; 938c2ecf20Sopenharmony_ci to->bh = bh; 948c2ecf20Sopenharmony_ci do { 958c2ecf20Sopenharmony_ci seq = read_seqbegin(&ufsi->meta_lock); 968c2ecf20Sopenharmony_ci to->key32 = *(__fs32 *)(to->p = v); 978c2ecf20Sopenharmony_ci for (p = from; p <= to && p->key32 == *(__fs32 *)p->p; p++) 988c2ecf20Sopenharmony_ci ; 998c2ecf20Sopenharmony_ci } while (read_seqretry(&ufsi->meta_lock, seq)); 1008c2ecf20Sopenharmony_ci return (p > to); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic inline int grow_chain64(struct ufs_inode_info *ufsi, 1048c2ecf20Sopenharmony_ci struct buffer_head *bh, __fs64 *v, 1058c2ecf20Sopenharmony_ci Indirect *from, Indirect *to) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci Indirect *p; 1088c2ecf20Sopenharmony_ci unsigned seq; 1098c2ecf20Sopenharmony_ci to->bh = bh; 1108c2ecf20Sopenharmony_ci do { 1118c2ecf20Sopenharmony_ci seq = read_seqbegin(&ufsi->meta_lock); 1128c2ecf20Sopenharmony_ci to->key64 = *(__fs64 *)(to->p = v); 1138c2ecf20Sopenharmony_ci for (p = from; p <= to && p->key64 == *(__fs64 *)p->p; p++) 1148c2ecf20Sopenharmony_ci ; 1158c2ecf20Sopenharmony_ci } while (read_seqretry(&ufsi->meta_lock, seq)); 1168c2ecf20Sopenharmony_ci return (p > to); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Returns the location of the fragment from 1218c2ecf20Sopenharmony_ci * the beginning of the filesystem. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic u64 ufs_frag_map(struct inode *inode, unsigned offsets[4], int depth) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 1278c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 1288c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 1298c2ecf20Sopenharmony_ci u64 mask = (u64) uspi->s_apbmask>>uspi->s_fpbshift; 1308c2ecf20Sopenharmony_ci int shift = uspi->s_apbshift-uspi->s_fpbshift; 1318c2ecf20Sopenharmony_ci Indirect chain[4], *q = chain; 1328c2ecf20Sopenharmony_ci unsigned *p; 1338c2ecf20Sopenharmony_ci unsigned flags = UFS_SB(sb)->s_flags; 1348c2ecf20Sopenharmony_ci u64 res = 0; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n", 1378c2ecf20Sopenharmony_ci uspi->s_fpbshift, uspi->s_apbmask, 1388c2ecf20Sopenharmony_ci (unsigned long long)mask); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (depth == 0) 1418c2ecf20Sopenharmony_ci goto no_block; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciagain: 1448c2ecf20Sopenharmony_ci p = offsets; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 1478c2ecf20Sopenharmony_ci goto ufs2; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (!grow_chain32(ufsi, NULL, &ufsi->i_u1.i_data[*p++], chain, q)) 1508c2ecf20Sopenharmony_ci goto changed; 1518c2ecf20Sopenharmony_ci if (!q->key32) 1528c2ecf20Sopenharmony_ci goto no_block; 1538c2ecf20Sopenharmony_ci while (--depth) { 1548c2ecf20Sopenharmony_ci __fs32 *ptr; 1558c2ecf20Sopenharmony_ci struct buffer_head *bh; 1568c2ecf20Sopenharmony_ci unsigned n = *p++; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci bh = sb_bread(sb, uspi->s_sbbase + 1598c2ecf20Sopenharmony_ci fs32_to_cpu(sb, q->key32) + (n>>shift)); 1608c2ecf20Sopenharmony_ci if (!bh) 1618c2ecf20Sopenharmony_ci goto no_block; 1628c2ecf20Sopenharmony_ci ptr = (__fs32 *)bh->b_data + (n & mask); 1638c2ecf20Sopenharmony_ci if (!grow_chain32(ufsi, bh, ptr, chain, ++q)) 1648c2ecf20Sopenharmony_ci goto changed; 1658c2ecf20Sopenharmony_ci if (!q->key32) 1668c2ecf20Sopenharmony_ci goto no_block; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci res = fs32_to_cpu(sb, q->key32); 1698c2ecf20Sopenharmony_ci goto found; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciufs2: 1728c2ecf20Sopenharmony_ci if (!grow_chain64(ufsi, NULL, &ufsi->i_u1.u2_i_data[*p++], chain, q)) 1738c2ecf20Sopenharmony_ci goto changed; 1748c2ecf20Sopenharmony_ci if (!q->key64) 1758c2ecf20Sopenharmony_ci goto no_block; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci while (--depth) { 1788c2ecf20Sopenharmony_ci __fs64 *ptr; 1798c2ecf20Sopenharmony_ci struct buffer_head *bh; 1808c2ecf20Sopenharmony_ci unsigned n = *p++; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci bh = sb_bread(sb, uspi->s_sbbase + 1838c2ecf20Sopenharmony_ci fs64_to_cpu(sb, q->key64) + (n>>shift)); 1848c2ecf20Sopenharmony_ci if (!bh) 1858c2ecf20Sopenharmony_ci goto no_block; 1868c2ecf20Sopenharmony_ci ptr = (__fs64 *)bh->b_data + (n & mask); 1878c2ecf20Sopenharmony_ci if (!grow_chain64(ufsi, bh, ptr, chain, ++q)) 1888c2ecf20Sopenharmony_ci goto changed; 1898c2ecf20Sopenharmony_ci if (!q->key64) 1908c2ecf20Sopenharmony_ci goto no_block; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci res = fs64_to_cpu(sb, q->key64); 1938c2ecf20Sopenharmony_cifound: 1948c2ecf20Sopenharmony_ci res += uspi->s_sbbase; 1958c2ecf20Sopenharmony_cino_block: 1968c2ecf20Sopenharmony_ci while (q > chain) { 1978c2ecf20Sopenharmony_ci brelse(q->bh); 1988c2ecf20Sopenharmony_ci q--; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci return res; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cichanged: 2038c2ecf20Sopenharmony_ci while (q > chain) { 2048c2ecf20Sopenharmony_ci brelse(q->bh); 2058c2ecf20Sopenharmony_ci q--; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci goto again; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/* 2118c2ecf20Sopenharmony_ci * Unpacking tails: we have a file with partial final block and 2128c2ecf20Sopenharmony_ci * we had been asked to extend it. If the fragment being written 2138c2ecf20Sopenharmony_ci * is within the same block, we need to extend the tail just to cover 2148c2ecf20Sopenharmony_ci * that fragment. Otherwise the tail is extended to full block. 2158c2ecf20Sopenharmony_ci * 2168c2ecf20Sopenharmony_ci * Note that we might need to create a _new_ tail, but that will 2178c2ecf20Sopenharmony_ci * be handled elsewhere; this is strictly for resizing old 2188c2ecf20Sopenharmony_ci * ones. 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_cistatic bool 2218c2ecf20Sopenharmony_ciufs_extend_tail(struct inode *inode, u64 writes_to, 2228c2ecf20Sopenharmony_ci int *err, struct page *locked_page) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 2258c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 2268c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 2278c2ecf20Sopenharmony_ci unsigned lastfrag = ufsi->i_lastfrag; /* it's a short file, so unsigned is enough */ 2288c2ecf20Sopenharmony_ci unsigned block = ufs_fragstoblks(lastfrag); 2298c2ecf20Sopenharmony_ci unsigned new_size; 2308c2ecf20Sopenharmony_ci void *p; 2318c2ecf20Sopenharmony_ci u64 tmp; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (writes_to < (lastfrag | uspi->s_fpbmask)) 2348c2ecf20Sopenharmony_ci new_size = (writes_to & uspi->s_fpbmask) + 1; 2358c2ecf20Sopenharmony_ci else 2368c2ecf20Sopenharmony_ci new_size = uspi->s_fpb; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, block); 2398c2ecf20Sopenharmony_ci tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p), 2408c2ecf20Sopenharmony_ci new_size - (lastfrag & uspi->s_fpbmask), err, 2418c2ecf20Sopenharmony_ci locked_page); 2428c2ecf20Sopenharmony_ci return tmp != 0; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/** 2468c2ecf20Sopenharmony_ci * ufs_inode_getfrag() - allocate new fragment(s) 2478c2ecf20Sopenharmony_ci * @inode: pointer to inode 2488c2ecf20Sopenharmony_ci * @index: number of block pointer within the inode's array. 2498c2ecf20Sopenharmony_ci * @new_fragment: number of new allocated fragment(s) 2508c2ecf20Sopenharmony_ci * @err: we set it if something wrong 2518c2ecf20Sopenharmony_ci * @new: we set it if we allocate new block 2528c2ecf20Sopenharmony_ci * @locked_page: for ufs_new_fragments() 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_cistatic u64 2558c2ecf20Sopenharmony_ciufs_inode_getfrag(struct inode *inode, unsigned index, 2568c2ecf20Sopenharmony_ci sector_t new_fragment, int *err, 2578c2ecf20Sopenharmony_ci int *new, struct page *locked_page) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 2608c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 2618c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 2628c2ecf20Sopenharmony_ci u64 tmp, goal, lastfrag; 2638c2ecf20Sopenharmony_ci unsigned nfrags = uspi->s_fpb; 2648c2ecf20Sopenharmony_ci void *p; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* TODO : to be done for write support 2678c2ecf20Sopenharmony_ci if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 2688c2ecf20Sopenharmony_ci goto ufs2; 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, index); 2728c2ecf20Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 2738c2ecf20Sopenharmony_ci if (tmp) 2748c2ecf20Sopenharmony_ci goto out; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci lastfrag = ufsi->i_lastfrag; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* will that be a new tail? */ 2798c2ecf20Sopenharmony_ci if (new_fragment < UFS_NDIR_FRAGMENT && new_fragment >= lastfrag) 2808c2ecf20Sopenharmony_ci nfrags = (new_fragment & uspi->s_fpbmask) + 1; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci goal = 0; 2838c2ecf20Sopenharmony_ci if (index) { 2848c2ecf20Sopenharmony_ci goal = ufs_data_ptr_to_cpu(sb, 2858c2ecf20Sopenharmony_ci ufs_get_direct_data_ptr(uspi, ufsi, index - 1)); 2868c2ecf20Sopenharmony_ci if (goal) 2878c2ecf20Sopenharmony_ci goal += uspi->s_fpb; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), 2908c2ecf20Sopenharmony_ci goal, nfrags, err, locked_page); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (!tmp) { 2938c2ecf20Sopenharmony_ci *err = -ENOSPC; 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (new) 2988c2ecf20Sopenharmony_ci *new = 1; 2998c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 3008c2ecf20Sopenharmony_ci if (IS_SYNC(inode)) 3018c2ecf20Sopenharmony_ci ufs_sync_inode (inode); 3028c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 3038c2ecf20Sopenharmony_ciout: 3048c2ecf20Sopenharmony_ci return tmp + uspi->s_sbbase; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* This part : To be implemented .... 3078c2ecf20Sopenharmony_ci Required only for writing, not required for READ-ONLY. 3088c2ecf20Sopenharmony_ciufs2: 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci u2_block = ufs_fragstoblks(fragment); 3118c2ecf20Sopenharmony_ci u2_blockoff = ufs_fragnum(fragment); 3128c2ecf20Sopenharmony_ci p = ufsi->i_u1.u2_i_data + block; 3138c2ecf20Sopenharmony_ci goal = 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cirepeat2: 3168c2ecf20Sopenharmony_ci tmp = fs32_to_cpu(sb, *p); 3178c2ecf20Sopenharmony_ci lastfrag = ufsi->i_lastfrag; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/** 3238c2ecf20Sopenharmony_ci * ufs_inode_getblock() - allocate new block 3248c2ecf20Sopenharmony_ci * @inode: pointer to inode 3258c2ecf20Sopenharmony_ci * @ind_block: block number of the indirect block 3268c2ecf20Sopenharmony_ci * @index: number of pointer within the indirect block 3278c2ecf20Sopenharmony_ci * @new_fragment: number of new allocated fragment 3288c2ecf20Sopenharmony_ci * (block will hold this fragment and also uspi->s_fpb-1) 3298c2ecf20Sopenharmony_ci * @err: see ufs_inode_getfrag() 3308c2ecf20Sopenharmony_ci * @new: see ufs_inode_getfrag() 3318c2ecf20Sopenharmony_ci * @locked_page: see ufs_inode_getfrag() 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_cistatic u64 3348c2ecf20Sopenharmony_ciufs_inode_getblock(struct inode *inode, u64 ind_block, 3358c2ecf20Sopenharmony_ci unsigned index, sector_t new_fragment, int *err, 3368c2ecf20Sopenharmony_ci int *new, struct page *locked_page) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 3398c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 3408c2ecf20Sopenharmony_ci int shift = uspi->s_apbshift - uspi->s_fpbshift; 3418c2ecf20Sopenharmony_ci u64 tmp = 0, goal; 3428c2ecf20Sopenharmony_ci struct buffer_head *bh; 3438c2ecf20Sopenharmony_ci void *p; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (!ind_block) 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci bh = sb_bread(sb, ind_block + (index >> shift)); 3498c2ecf20Sopenharmony_ci if (unlikely(!bh)) { 3508c2ecf20Sopenharmony_ci *err = -EIO; 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci index &= uspi->s_apbmask >> uspi->s_fpbshift; 3558c2ecf20Sopenharmony_ci if (uspi->fs_magic == UFS2_MAGIC) 3568c2ecf20Sopenharmony_ci p = (__fs64 *)bh->b_data + index; 3578c2ecf20Sopenharmony_ci else 3588c2ecf20Sopenharmony_ci p = (__fs32 *)bh->b_data + index; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 3618c2ecf20Sopenharmony_ci if (tmp) 3628c2ecf20Sopenharmony_ci goto out; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (index && (uspi->fs_magic == UFS2_MAGIC ? 3658c2ecf20Sopenharmony_ci (tmp = fs64_to_cpu(sb, ((__fs64 *)bh->b_data)[index-1])) : 3668c2ecf20Sopenharmony_ci (tmp = fs32_to_cpu(sb, ((__fs32 *)bh->b_data)[index-1])))) 3678c2ecf20Sopenharmony_ci goal = tmp + uspi->s_fpb; 3688c2ecf20Sopenharmony_ci else 3698c2ecf20Sopenharmony_ci goal = bh->b_blocknr + uspi->s_fpb; 3708c2ecf20Sopenharmony_ci tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, 3718c2ecf20Sopenharmony_ci uspi->s_fpb, err, locked_page); 3728c2ecf20Sopenharmony_ci if (!tmp) 3738c2ecf20Sopenharmony_ci goto out; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (new) 3768c2ecf20Sopenharmony_ci *new = 1; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 3798c2ecf20Sopenharmony_ci if (IS_SYNC(inode)) 3808c2ecf20Sopenharmony_ci sync_dirty_buffer(bh); 3818c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 3828c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 3838c2ecf20Sopenharmony_ciout: 3848c2ecf20Sopenharmony_ci brelse (bh); 3858c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 3868c2ecf20Sopenharmony_ci if (tmp) 3878c2ecf20Sopenharmony_ci tmp += uspi->s_sbbase; 3888c2ecf20Sopenharmony_ci return tmp; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci/** 3928c2ecf20Sopenharmony_ci * ufs_getfrag_block() - `get_block_t' function, interface between UFS and 3938c2ecf20Sopenharmony_ci * readpage, writepage and so on 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 3998c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 4008c2ecf20Sopenharmony_ci int err = 0, new = 0; 4018c2ecf20Sopenharmony_ci unsigned offsets[4]; 4028c2ecf20Sopenharmony_ci int depth = ufs_block_to_path(inode, fragment >> uspi->s_fpbshift, offsets); 4038c2ecf20Sopenharmony_ci u64 phys64 = 0; 4048c2ecf20Sopenharmony_ci unsigned frag = fragment & uspi->s_fpbmask; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci phys64 = ufs_frag_map(inode, offsets, depth); 4078c2ecf20Sopenharmony_ci if (!create) 4088c2ecf20Sopenharmony_ci goto done; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (phys64) { 4118c2ecf20Sopenharmony_ci if (fragment >= UFS_NDIR_FRAGMENT) 4128c2ecf20Sopenharmony_ci goto done; 4138c2ecf20Sopenharmony_ci read_seqlock_excl(&UFS_I(inode)->meta_lock); 4148c2ecf20Sopenharmony_ci if (fragment < UFS_I(inode)->i_lastfrag) { 4158c2ecf20Sopenharmony_ci read_sequnlock_excl(&UFS_I(inode)->meta_lock); 4168c2ecf20Sopenharmony_ci goto done; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci read_sequnlock_excl(&UFS_I(inode)->meta_lock); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci /* This code entered only while writing ....? */ 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci mutex_lock(&UFS_I(inode)->truncate_mutex); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); 4258c2ecf20Sopenharmony_ci if (unlikely(!depth)) { 4268c2ecf20Sopenharmony_ci ufs_warning(sb, "ufs_get_block", "block > big"); 4278c2ecf20Sopenharmony_ci err = -EIO; 4288c2ecf20Sopenharmony_ci goto out; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (UFS_I(inode)->i_lastfrag < UFS_NDIR_FRAGMENT) { 4328c2ecf20Sopenharmony_ci unsigned lastfrag = UFS_I(inode)->i_lastfrag; 4338c2ecf20Sopenharmony_ci unsigned tailfrags = lastfrag & uspi->s_fpbmask; 4348c2ecf20Sopenharmony_ci if (tailfrags && fragment >= lastfrag) { 4358c2ecf20Sopenharmony_ci if (!ufs_extend_tail(inode, fragment, 4368c2ecf20Sopenharmony_ci &err, bh_result->b_page)) 4378c2ecf20Sopenharmony_ci goto out; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (depth == 1) { 4428c2ecf20Sopenharmony_ci phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, 4438c2ecf20Sopenharmony_ci &err, &new, bh_result->b_page); 4448c2ecf20Sopenharmony_ci } else { 4458c2ecf20Sopenharmony_ci int i; 4468c2ecf20Sopenharmony_ci phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, 4478c2ecf20Sopenharmony_ci &err, NULL, NULL); 4488c2ecf20Sopenharmony_ci for (i = 1; i < depth - 1; i++) 4498c2ecf20Sopenharmony_ci phys64 = ufs_inode_getblock(inode, phys64, offsets[i], 4508c2ecf20Sopenharmony_ci fragment, &err, NULL, NULL); 4518c2ecf20Sopenharmony_ci phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1], 4528c2ecf20Sopenharmony_ci fragment, &err, &new, bh_result->b_page); 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ciout: 4558c2ecf20Sopenharmony_ci if (phys64) { 4568c2ecf20Sopenharmony_ci phys64 += frag; 4578c2ecf20Sopenharmony_ci map_bh(bh_result, sb, phys64); 4588c2ecf20Sopenharmony_ci if (new) 4598c2ecf20Sopenharmony_ci set_buffer_new(bh_result); 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci mutex_unlock(&UFS_I(inode)->truncate_mutex); 4628c2ecf20Sopenharmony_ci return err; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cidone: 4658c2ecf20Sopenharmony_ci if (phys64) 4668c2ecf20Sopenharmony_ci map_bh(bh_result, sb, phys64 + frag); 4678c2ecf20Sopenharmony_ci return 0; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic int ufs_writepage(struct page *page, struct writeback_control *wbc) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci return block_write_full_page(page,ufs_getfrag_block,wbc); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int ufs_readpage(struct file *file, struct page *page) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci return block_read_full_page(page,ufs_getfrag_block); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ciint ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci return __block_write_begin(page, pos, len, ufs_getfrag_block); 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic void ufs_truncate_blocks(struct inode *); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic void ufs_write_failed(struct address_space *mapping, loff_t to) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (to > inode->i_size) { 4928c2ecf20Sopenharmony_ci truncate_pagecache(inode, inode->i_size); 4938c2ecf20Sopenharmony_ci ufs_truncate_blocks(inode); 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int ufs_write_begin(struct file *file, struct address_space *mapping, 4988c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned flags, 4998c2ecf20Sopenharmony_ci struct page **pagep, void **fsdata) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci int ret; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci ret = block_write_begin(mapping, pos, len, flags, pagep, 5048c2ecf20Sopenharmony_ci ufs_getfrag_block); 5058c2ecf20Sopenharmony_ci if (unlikely(ret)) 5068c2ecf20Sopenharmony_ci ufs_write_failed(mapping, pos + len); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return ret; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic int ufs_write_end(struct file *file, struct address_space *mapping, 5128c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned copied, 5138c2ecf20Sopenharmony_ci struct page *page, void *fsdata) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci int ret; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); 5188c2ecf20Sopenharmony_ci if (ret < len) 5198c2ecf20Sopenharmony_ci ufs_write_failed(mapping, pos + len); 5208c2ecf20Sopenharmony_ci return ret; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic sector_t ufs_bmap(struct address_space *mapping, sector_t block) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci return generic_block_bmap(mapping,block,ufs_getfrag_block); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ciconst struct address_space_operations ufs_aops = { 5298c2ecf20Sopenharmony_ci .readpage = ufs_readpage, 5308c2ecf20Sopenharmony_ci .writepage = ufs_writepage, 5318c2ecf20Sopenharmony_ci .write_begin = ufs_write_begin, 5328c2ecf20Sopenharmony_ci .write_end = ufs_write_end, 5338c2ecf20Sopenharmony_ci .bmap = ufs_bmap 5348c2ecf20Sopenharmony_ci}; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void ufs_set_inode_ops(struct inode *inode) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 5398c2ecf20Sopenharmony_ci inode->i_op = &ufs_file_inode_operations; 5408c2ecf20Sopenharmony_ci inode->i_fop = &ufs_file_operations; 5418c2ecf20Sopenharmony_ci inode->i_mapping->a_ops = &ufs_aops; 5428c2ecf20Sopenharmony_ci } else if (S_ISDIR(inode->i_mode)) { 5438c2ecf20Sopenharmony_ci inode->i_op = &ufs_dir_inode_operations; 5448c2ecf20Sopenharmony_ci inode->i_fop = &ufs_dir_operations; 5458c2ecf20Sopenharmony_ci inode->i_mapping->a_ops = &ufs_aops; 5468c2ecf20Sopenharmony_ci } else if (S_ISLNK(inode->i_mode)) { 5478c2ecf20Sopenharmony_ci if (!inode->i_blocks) { 5488c2ecf20Sopenharmony_ci inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink; 5498c2ecf20Sopenharmony_ci inode->i_op = &simple_symlink_inode_operations; 5508c2ecf20Sopenharmony_ci } else { 5518c2ecf20Sopenharmony_ci inode->i_mapping->a_ops = &ufs_aops; 5528c2ecf20Sopenharmony_ci inode->i_op = &page_symlink_inode_operations; 5538c2ecf20Sopenharmony_ci inode_nohighmem(inode); 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci } else 5568c2ecf20Sopenharmony_ci init_special_inode(inode, inode->i_mode, 5578c2ecf20Sopenharmony_ci ufs_get_inode_dev(inode->i_sb, UFS_I(inode))); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 5638c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 5648c2ecf20Sopenharmony_ci umode_t mode; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* 5678c2ecf20Sopenharmony_ci * Copy data to the in-core inode. 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ci inode->i_mode = mode = fs16_to_cpu(sb, ufs_inode->ui_mode); 5708c2ecf20Sopenharmony_ci set_nlink(inode, fs16_to_cpu(sb, ufs_inode->ui_nlink)); 5718c2ecf20Sopenharmony_ci if (inode->i_nlink == 0) 5728c2ecf20Sopenharmony_ci return -ESTALE; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* 5758c2ecf20Sopenharmony_ci * Linux now has 32-bit uid and gid, so we can support EFT. 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_ci i_uid_write(inode, ufs_get_inode_uid(sb, ufs_inode)); 5788c2ecf20Sopenharmony_ci i_gid_write(inode, ufs_get_inode_gid(sb, ufs_inode)); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci inode->i_size = fs64_to_cpu(sb, ufs_inode->ui_size); 5818c2ecf20Sopenharmony_ci inode->i_atime.tv_sec = (signed)fs32_to_cpu(sb, ufs_inode->ui_atime.tv_sec); 5828c2ecf20Sopenharmony_ci inode->i_ctime.tv_sec = (signed)fs32_to_cpu(sb, ufs_inode->ui_ctime.tv_sec); 5838c2ecf20Sopenharmony_ci inode->i_mtime.tv_sec = (signed)fs32_to_cpu(sb, ufs_inode->ui_mtime.tv_sec); 5848c2ecf20Sopenharmony_ci inode->i_mtime.tv_nsec = 0; 5858c2ecf20Sopenharmony_ci inode->i_atime.tv_nsec = 0; 5868c2ecf20Sopenharmony_ci inode->i_ctime.tv_nsec = 0; 5878c2ecf20Sopenharmony_ci inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks); 5888c2ecf20Sopenharmony_ci inode->i_generation = fs32_to_cpu(sb, ufs_inode->ui_gen); 5898c2ecf20Sopenharmony_ci ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags); 5908c2ecf20Sopenharmony_ci ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); 5918c2ecf20Sopenharmony_ci ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { 5958c2ecf20Sopenharmony_ci memcpy(ufsi->i_u1.i_data, &ufs_inode->ui_u2.ui_addr, 5968c2ecf20Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_addr)); 5978c2ecf20Sopenharmony_ci } else { 5988c2ecf20Sopenharmony_ci memcpy(ufsi->i_u1.i_symlink, ufs_inode->ui_u2.ui_symlink, 5998c2ecf20Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_symlink) - 1); 6008c2ecf20Sopenharmony_ci ufsi->i_u1.i_symlink[sizeof(ufs_inode->ui_u2.ui_symlink) - 1] = 0; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 6088c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 6098c2ecf20Sopenharmony_ci umode_t mode; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino); 6128c2ecf20Sopenharmony_ci /* 6138c2ecf20Sopenharmony_ci * Copy data to the in-core inode. 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_ci inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode); 6168c2ecf20Sopenharmony_ci set_nlink(inode, fs16_to_cpu(sb, ufs2_inode->ui_nlink)); 6178c2ecf20Sopenharmony_ci if (inode->i_nlink == 0) 6188c2ecf20Sopenharmony_ci return -ESTALE; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* 6218c2ecf20Sopenharmony_ci * Linux now has 32-bit uid and gid, so we can support EFT. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci i_uid_write(inode, fs32_to_cpu(sb, ufs2_inode->ui_uid)); 6248c2ecf20Sopenharmony_ci i_gid_write(inode, fs32_to_cpu(sb, ufs2_inode->ui_gid)); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size); 6278c2ecf20Sopenharmony_ci inode->i_atime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_atime); 6288c2ecf20Sopenharmony_ci inode->i_ctime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_ctime); 6298c2ecf20Sopenharmony_ci inode->i_mtime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_mtime); 6308c2ecf20Sopenharmony_ci inode->i_atime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_atimensec); 6318c2ecf20Sopenharmony_ci inode->i_ctime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_ctimensec); 6328c2ecf20Sopenharmony_ci inode->i_mtime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_mtimensec); 6338c2ecf20Sopenharmony_ci inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks); 6348c2ecf20Sopenharmony_ci inode->i_generation = fs32_to_cpu(sb, ufs2_inode->ui_gen); 6358c2ecf20Sopenharmony_ci ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags); 6368c2ecf20Sopenharmony_ci /* 6378c2ecf20Sopenharmony_ci ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); 6388c2ecf20Sopenharmony_ci ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); 6398c2ecf20Sopenharmony_ci */ 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { 6428c2ecf20Sopenharmony_ci memcpy(ufsi->i_u1.u2_i_data, &ufs2_inode->ui_u2.ui_addr, 6438c2ecf20Sopenharmony_ci sizeof(ufs2_inode->ui_u2.ui_addr)); 6448c2ecf20Sopenharmony_ci } else { 6458c2ecf20Sopenharmony_ci memcpy(ufsi->i_u1.i_symlink, ufs2_inode->ui_u2.ui_symlink, 6468c2ecf20Sopenharmony_ci sizeof(ufs2_inode->ui_u2.ui_symlink) - 1); 6478c2ecf20Sopenharmony_ci ufsi->i_u1.i_symlink[sizeof(ufs2_inode->ui_u2.ui_symlink) - 1] = 0; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistruct inode *ufs_iget(struct super_block *sb, unsigned long ino) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi; 6558c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 6568c2ecf20Sopenharmony_ci struct buffer_head * bh; 6578c2ecf20Sopenharmony_ci struct inode *inode; 6588c2ecf20Sopenharmony_ci int err = -EIO; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci UFSD("ENTER, ino %lu\n", ino); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (ino < UFS_ROOTINO || ino > (uspi->s_ncg * uspi->s_ipg)) { 6638c2ecf20Sopenharmony_ci ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n", 6648c2ecf20Sopenharmony_ci ino); 6658c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci inode = iget_locked(sb, ino); 6698c2ecf20Sopenharmony_ci if (!inode) 6708c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 6718c2ecf20Sopenharmony_ci if (!(inode->i_state & I_NEW)) 6728c2ecf20Sopenharmony_ci return inode; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci ufsi = UFS_I(inode); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino)); 6778c2ecf20Sopenharmony_ci if (!bh) { 6788c2ecf20Sopenharmony_ci ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n", 6798c2ecf20Sopenharmony_ci inode->i_ino); 6808c2ecf20Sopenharmony_ci goto bad_inode; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci if ((UFS_SB(sb)->s_flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { 6838c2ecf20Sopenharmony_ci struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci err = ufs2_read_inode(inode, 6868c2ecf20Sopenharmony_ci ufs2_inode + ufs_inotofsbo(inode->i_ino)); 6878c2ecf20Sopenharmony_ci } else { 6888c2ecf20Sopenharmony_ci struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci err = ufs1_read_inode(inode, 6918c2ecf20Sopenharmony_ci ufs_inode + ufs_inotofsbo(inode->i_ino)); 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci brelse(bh); 6948c2ecf20Sopenharmony_ci if (err) 6958c2ecf20Sopenharmony_ci goto bad_inode; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci inode_inc_iversion(inode); 6988c2ecf20Sopenharmony_ci ufsi->i_lastfrag = 6998c2ecf20Sopenharmony_ci (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift; 7008c2ecf20Sopenharmony_ci ufsi->i_dir_start_lookup = 0; 7018c2ecf20Sopenharmony_ci ufsi->i_osync = 0; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci ufs_set_inode_ops(inode); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 7068c2ecf20Sopenharmony_ci unlock_new_inode(inode); 7078c2ecf20Sopenharmony_ci return inode; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cibad_inode: 7108c2ecf20Sopenharmony_ci iget_failed(inode); 7118c2ecf20Sopenharmony_ci return ERR_PTR(err); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 7178c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); 7208c2ecf20Sopenharmony_ci ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci ufs_set_inode_uid(sb, ufs_inode, i_uid_read(inode)); 7238c2ecf20Sopenharmony_ci ufs_set_inode_gid(sb, ufs_inode, i_gid_read(inode)); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); 7268c2ecf20Sopenharmony_ci ufs_inode->ui_atime.tv_sec = cpu_to_fs32(sb, inode->i_atime.tv_sec); 7278c2ecf20Sopenharmony_ci ufs_inode->ui_atime.tv_usec = 0; 7288c2ecf20Sopenharmony_ci ufs_inode->ui_ctime.tv_sec = cpu_to_fs32(sb, inode->i_ctime.tv_sec); 7298c2ecf20Sopenharmony_ci ufs_inode->ui_ctime.tv_usec = 0; 7308c2ecf20Sopenharmony_ci ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, inode->i_mtime.tv_sec); 7318c2ecf20Sopenharmony_ci ufs_inode->ui_mtime.tv_usec = 0; 7328c2ecf20Sopenharmony_ci ufs_inode->ui_blocks = cpu_to_fs32(sb, inode->i_blocks); 7338c2ecf20Sopenharmony_ci ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); 7348c2ecf20Sopenharmony_ci ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if ((UFS_SB(sb)->s_flags & UFS_UID_MASK) == UFS_UID_EFT) { 7378c2ecf20Sopenharmony_ci ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, ufsi->i_shadow); 7388c2ecf20Sopenharmony_ci ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, ufsi->i_oeftflag); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { 7428c2ecf20Sopenharmony_ci /* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ 7438c2ecf20Sopenharmony_ci ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.i_data[0]; 7448c2ecf20Sopenharmony_ci } else if (inode->i_blocks) { 7458c2ecf20Sopenharmony_ci memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.i_data, 7468c2ecf20Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_addr)); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci else { 7498c2ecf20Sopenharmony_ci memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink, 7508c2ecf20Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_symlink)); 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (!inode->i_nlink) 7548c2ecf20Sopenharmony_ci memset (ufs_inode, 0, sizeof(struct ufs_inode)); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic void ufs2_update_inode(struct inode *inode, struct ufs2_inode *ufs_inode) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 7608c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci UFSD("ENTER\n"); 7638c2ecf20Sopenharmony_ci ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); 7648c2ecf20Sopenharmony_ci ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci ufs_inode->ui_uid = cpu_to_fs32(sb, i_uid_read(inode)); 7678c2ecf20Sopenharmony_ci ufs_inode->ui_gid = cpu_to_fs32(sb, i_gid_read(inode)); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); 7708c2ecf20Sopenharmony_ci ufs_inode->ui_atime = cpu_to_fs64(sb, inode->i_atime.tv_sec); 7718c2ecf20Sopenharmony_ci ufs_inode->ui_atimensec = cpu_to_fs32(sb, inode->i_atime.tv_nsec); 7728c2ecf20Sopenharmony_ci ufs_inode->ui_ctime = cpu_to_fs64(sb, inode->i_ctime.tv_sec); 7738c2ecf20Sopenharmony_ci ufs_inode->ui_ctimensec = cpu_to_fs32(sb, inode->i_ctime.tv_nsec); 7748c2ecf20Sopenharmony_ci ufs_inode->ui_mtime = cpu_to_fs64(sb, inode->i_mtime.tv_sec); 7758c2ecf20Sopenharmony_ci ufs_inode->ui_mtimensec = cpu_to_fs32(sb, inode->i_mtime.tv_nsec); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci ufs_inode->ui_blocks = cpu_to_fs64(sb, inode->i_blocks); 7788c2ecf20Sopenharmony_ci ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); 7798c2ecf20Sopenharmony_ci ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { 7828c2ecf20Sopenharmony_ci /* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ 7838c2ecf20Sopenharmony_ci ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.u2_i_data[0]; 7848c2ecf20Sopenharmony_ci } else if (inode->i_blocks) { 7858c2ecf20Sopenharmony_ci memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.u2_i_data, 7868c2ecf20Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_addr)); 7878c2ecf20Sopenharmony_ci } else { 7888c2ecf20Sopenharmony_ci memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink, 7898c2ecf20Sopenharmony_ci sizeof(ufs_inode->ui_u2.ui_symlink)); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (!inode->i_nlink) 7938c2ecf20Sopenharmony_ci memset (ufs_inode, 0, sizeof(struct ufs2_inode)); 7948c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic int ufs_update_inode(struct inode * inode, int do_sync) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 8008c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 8018c2ecf20Sopenharmony_ci struct buffer_head * bh; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci UFSD("ENTER, ino %lu\n", inode->i_ino); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (inode->i_ino < UFS_ROOTINO || 8068c2ecf20Sopenharmony_ci inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { 8078c2ecf20Sopenharmony_ci ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); 8088c2ecf20Sopenharmony_ci return -1; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci bh = sb_bread(sb, ufs_inotofsba(inode->i_ino)); 8128c2ecf20Sopenharmony_ci if (!bh) { 8138c2ecf20Sopenharmony_ci ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); 8148c2ecf20Sopenharmony_ci return -1; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci if (uspi->fs_magic == UFS2_MAGIC) { 8178c2ecf20Sopenharmony_ci struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci ufs2_update_inode(inode, 8208c2ecf20Sopenharmony_ci ufs2_inode + ufs_inotofsbo(inode->i_ino)); 8218c2ecf20Sopenharmony_ci } else { 8228c2ecf20Sopenharmony_ci struct ufs_inode *ufs_inode = (struct ufs_inode *) bh->b_data; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci ufs1_update_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino)); 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 8288c2ecf20Sopenharmony_ci if (do_sync) 8298c2ecf20Sopenharmony_ci sync_dirty_buffer(bh); 8308c2ecf20Sopenharmony_ci brelse (bh); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci UFSD("EXIT\n"); 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ciint ufs_write_inode(struct inode *inode, struct writeback_control *wbc) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci return ufs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL); 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ciint ufs_sync_inode (struct inode *inode) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci return ufs_update_inode (inode, 1); 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_civoid ufs_evict_inode(struct inode * inode) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci int want_delete = 0; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (!inode->i_nlink && !is_bad_inode(inode)) 8518c2ecf20Sopenharmony_ci want_delete = 1; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 8548c2ecf20Sopenharmony_ci if (want_delete) { 8558c2ecf20Sopenharmony_ci inode->i_size = 0; 8568c2ecf20Sopenharmony_ci if (inode->i_blocks && 8578c2ecf20Sopenharmony_ci (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || 8588c2ecf20Sopenharmony_ci S_ISLNK(inode->i_mode))) 8598c2ecf20Sopenharmony_ci ufs_truncate_blocks(inode); 8608c2ecf20Sopenharmony_ci ufs_update_inode(inode, inode_needs_sync(inode)); 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci invalidate_inode_buffers(inode); 8648c2ecf20Sopenharmony_ci clear_inode(inode); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (want_delete) 8678c2ecf20Sopenharmony_ci ufs_free_inode(inode); 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistruct to_free { 8718c2ecf20Sopenharmony_ci struct inode *inode; 8728c2ecf20Sopenharmony_ci u64 to; 8738c2ecf20Sopenharmony_ci unsigned count; 8748c2ecf20Sopenharmony_ci}; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic inline void free_data(struct to_free *ctx, u64 from, unsigned count) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci if (ctx->count && ctx->to != from) { 8798c2ecf20Sopenharmony_ci ufs_free_blocks(ctx->inode, ctx->to - ctx->count, ctx->count); 8808c2ecf20Sopenharmony_ci ctx->count = 0; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci ctx->count += count; 8838c2ecf20Sopenharmony_ci ctx->to = from + count; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic void ufs_trunc_direct(struct inode *inode) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 8918c2ecf20Sopenharmony_ci struct super_block * sb; 8928c2ecf20Sopenharmony_ci struct ufs_sb_private_info * uspi; 8938c2ecf20Sopenharmony_ci void *p; 8948c2ecf20Sopenharmony_ci u64 frag1, frag2, frag3, frag4, block1, block2; 8958c2ecf20Sopenharmony_ci struct to_free ctx = {.inode = inode}; 8968c2ecf20Sopenharmony_ci unsigned i, tmp; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci UFSD("ENTER: ino %lu\n", inode->i_ino); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci sb = inode->i_sb; 9018c2ecf20Sopenharmony_ci uspi = UFS_SB(sb)->s_uspi; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci frag1 = DIRECT_FRAGMENT; 9048c2ecf20Sopenharmony_ci frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); 9058c2ecf20Sopenharmony_ci frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); 9068c2ecf20Sopenharmony_ci frag3 = frag4 & ~uspi->s_fpbmask; 9078c2ecf20Sopenharmony_ci block1 = block2 = 0; 9088c2ecf20Sopenharmony_ci if (frag2 > frag3) { 9098c2ecf20Sopenharmony_ci frag2 = frag4; 9108c2ecf20Sopenharmony_ci frag3 = frag4 = 0; 9118c2ecf20Sopenharmony_ci } else if (frag2 < frag3) { 9128c2ecf20Sopenharmony_ci block1 = ufs_fragstoblks (frag2); 9138c2ecf20Sopenharmony_ci block2 = ufs_fragstoblks (frag3); 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu," 9178c2ecf20Sopenharmony_ci " frag3 %llu, frag4 %llu\n", inode->i_ino, 9188c2ecf20Sopenharmony_ci (unsigned long long)frag1, (unsigned long long)frag2, 9198c2ecf20Sopenharmony_ci (unsigned long long)block1, (unsigned long long)block2, 9208c2ecf20Sopenharmony_ci (unsigned long long)frag3, (unsigned long long)frag4); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (frag1 >= frag2) 9238c2ecf20Sopenharmony_ci goto next1; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* 9268c2ecf20Sopenharmony_ci * Free first free fragments 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1)); 9298c2ecf20Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 9308c2ecf20Sopenharmony_ci if (!tmp ) 9318c2ecf20Sopenharmony_ci ufs_panic (sb, "ufs_trunc_direct", "internal error"); 9328c2ecf20Sopenharmony_ci frag2 -= frag1; 9338c2ecf20Sopenharmony_ci frag1 = ufs_fragnum (frag1); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci ufs_free_fragments(inode, tmp + frag1, frag2); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cinext1: 9388c2ecf20Sopenharmony_ci /* 9398c2ecf20Sopenharmony_ci * Free whole blocks 9408c2ecf20Sopenharmony_ci */ 9418c2ecf20Sopenharmony_ci for (i = block1 ; i < block2; i++) { 9428c2ecf20Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, i); 9438c2ecf20Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 9448c2ecf20Sopenharmony_ci if (!tmp) 9458c2ecf20Sopenharmony_ci continue; 9468c2ecf20Sopenharmony_ci write_seqlock(&ufsi->meta_lock); 9478c2ecf20Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 9488c2ecf20Sopenharmony_ci write_sequnlock(&ufsi->meta_lock); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci free_data(&ctx, tmp, uspi->s_fpb); 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci free_data(&ctx, 0, 0); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (frag3 >= frag4) 9568c2ecf20Sopenharmony_ci goto next3; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci /* 9598c2ecf20Sopenharmony_ci * Free last free fragments 9608c2ecf20Sopenharmony_ci */ 9618c2ecf20Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3)); 9628c2ecf20Sopenharmony_ci tmp = ufs_data_ptr_to_cpu(sb, p); 9638c2ecf20Sopenharmony_ci if (!tmp ) 9648c2ecf20Sopenharmony_ci ufs_panic(sb, "ufs_truncate_direct", "internal error"); 9658c2ecf20Sopenharmony_ci frag4 = ufs_fragnum (frag4); 9668c2ecf20Sopenharmony_ci write_seqlock(&ufsi->meta_lock); 9678c2ecf20Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 9688c2ecf20Sopenharmony_ci write_sequnlock(&ufsi->meta_lock); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci ufs_free_fragments (inode, tmp, frag4); 9718c2ecf20Sopenharmony_ci next3: 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci UFSD("EXIT: ino %lu\n", inode->i_ino); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic void free_full_branch(struct inode *inode, u64 ind_block, int depth) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 9798c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 9808c2ecf20Sopenharmony_ci struct ufs_buffer_head *ubh = ubh_bread(sb, ind_block, uspi->s_bsize); 9818c2ecf20Sopenharmony_ci unsigned i; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (!ubh) 9848c2ecf20Sopenharmony_ci return; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (--depth) { 9878c2ecf20Sopenharmony_ci for (i = 0; i < uspi->s_apb; i++) { 9888c2ecf20Sopenharmony_ci void *p = ubh_get_data_ptr(uspi, ubh, i); 9898c2ecf20Sopenharmony_ci u64 block = ufs_data_ptr_to_cpu(sb, p); 9908c2ecf20Sopenharmony_ci if (block) 9918c2ecf20Sopenharmony_ci free_full_branch(inode, block, depth); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci } else { 9948c2ecf20Sopenharmony_ci struct to_free ctx = {.inode = inode}; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci for (i = 0; i < uspi->s_apb; i++) { 9978c2ecf20Sopenharmony_ci void *p = ubh_get_data_ptr(uspi, ubh, i); 9988c2ecf20Sopenharmony_ci u64 block = ufs_data_ptr_to_cpu(sb, p); 9998c2ecf20Sopenharmony_ci if (block) 10008c2ecf20Sopenharmony_ci free_data(&ctx, block, uspi->s_fpb); 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci free_data(&ctx, 0, 0); 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci ubh_bforget(ubh); 10068c2ecf20Sopenharmony_ci ufs_free_blocks(inode, ind_block, uspi->s_fpb); 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cistatic void free_branch_tail(struct inode *inode, unsigned from, struct ufs_buffer_head *ubh, int depth) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 10128c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 10138c2ecf20Sopenharmony_ci unsigned i; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (--depth) { 10168c2ecf20Sopenharmony_ci for (i = from; i < uspi->s_apb ; i++) { 10178c2ecf20Sopenharmony_ci void *p = ubh_get_data_ptr(uspi, ubh, i); 10188c2ecf20Sopenharmony_ci u64 block = ufs_data_ptr_to_cpu(sb, p); 10198c2ecf20Sopenharmony_ci if (block) { 10208c2ecf20Sopenharmony_ci write_seqlock(&UFS_I(inode)->meta_lock); 10218c2ecf20Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 10228c2ecf20Sopenharmony_ci write_sequnlock(&UFS_I(inode)->meta_lock); 10238c2ecf20Sopenharmony_ci ubh_mark_buffer_dirty(ubh); 10248c2ecf20Sopenharmony_ci free_full_branch(inode, block, depth); 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci } else { 10288c2ecf20Sopenharmony_ci struct to_free ctx = {.inode = inode}; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci for (i = from; i < uspi->s_apb; i++) { 10318c2ecf20Sopenharmony_ci void *p = ubh_get_data_ptr(uspi, ubh, i); 10328c2ecf20Sopenharmony_ci u64 block = ufs_data_ptr_to_cpu(sb, p); 10338c2ecf20Sopenharmony_ci if (block) { 10348c2ecf20Sopenharmony_ci write_seqlock(&UFS_I(inode)->meta_lock); 10358c2ecf20Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 10368c2ecf20Sopenharmony_ci write_sequnlock(&UFS_I(inode)->meta_lock); 10378c2ecf20Sopenharmony_ci ubh_mark_buffer_dirty(ubh); 10388c2ecf20Sopenharmony_ci free_data(&ctx, block, uspi->s_fpb); 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci free_data(&ctx, 0, 0); 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci if (IS_SYNC(inode) && ubh_buffer_dirty(ubh)) 10448c2ecf20Sopenharmony_ci ubh_sync_block(ubh); 10458c2ecf20Sopenharmony_ci ubh_brelse(ubh); 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cistatic int ufs_alloc_lastblock(struct inode *inode, loff_t size) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci int err = 0; 10518c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 10528c2ecf20Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 10538c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 10548c2ecf20Sopenharmony_ci unsigned i, end; 10558c2ecf20Sopenharmony_ci sector_t lastfrag; 10568c2ecf20Sopenharmony_ci struct page *lastpage; 10578c2ecf20Sopenharmony_ci struct buffer_head *bh; 10588c2ecf20Sopenharmony_ci u64 phys64; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci lastfrag = (size + uspi->s_fsize - 1) >> uspi->s_fshift; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (!lastfrag) 10638c2ecf20Sopenharmony_ci goto out; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci lastfrag--; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci lastpage = ufs_get_locked_page(mapping, lastfrag >> 10688c2ecf20Sopenharmony_ci (PAGE_SHIFT - inode->i_blkbits)); 10698c2ecf20Sopenharmony_ci if (IS_ERR(lastpage)) { 10708c2ecf20Sopenharmony_ci err = -EIO; 10718c2ecf20Sopenharmony_ci goto out; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci end = lastfrag & ((1 << (PAGE_SHIFT - inode->i_blkbits)) - 1); 10758c2ecf20Sopenharmony_ci bh = page_buffers(lastpage); 10768c2ecf20Sopenharmony_ci for (i = 0; i < end; ++i) 10778c2ecf20Sopenharmony_ci bh = bh->b_this_page; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci err = ufs_getfrag_block(inode, lastfrag, bh, 1); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (unlikely(err)) 10838c2ecf20Sopenharmony_ci goto out_unlock; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (buffer_new(bh)) { 10868c2ecf20Sopenharmony_ci clear_buffer_new(bh); 10878c2ecf20Sopenharmony_ci clean_bdev_bh_alias(bh); 10888c2ecf20Sopenharmony_ci /* 10898c2ecf20Sopenharmony_ci * we do not zeroize fragment, because of 10908c2ecf20Sopenharmony_ci * if it maped to hole, it already contains zeroes 10918c2ecf20Sopenharmony_ci */ 10928c2ecf20Sopenharmony_ci set_buffer_uptodate(bh); 10938c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 10948c2ecf20Sopenharmony_ci set_page_dirty(lastpage); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (lastfrag >= UFS_IND_FRAGMENT) { 10988c2ecf20Sopenharmony_ci end = uspi->s_fpb - ufs_fragnum(lastfrag) - 1; 10998c2ecf20Sopenharmony_ci phys64 = bh->b_blocknr + 1; 11008c2ecf20Sopenharmony_ci for (i = 0; i < end; ++i) { 11018c2ecf20Sopenharmony_ci bh = sb_getblk(sb, i + phys64); 11028c2ecf20Sopenharmony_ci lock_buffer(bh); 11038c2ecf20Sopenharmony_ci memset(bh->b_data, 0, sb->s_blocksize); 11048c2ecf20Sopenharmony_ci set_buffer_uptodate(bh); 11058c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 11068c2ecf20Sopenharmony_ci unlock_buffer(bh); 11078c2ecf20Sopenharmony_ci sync_dirty_buffer(bh); 11088c2ecf20Sopenharmony_ci brelse(bh); 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ciout_unlock: 11128c2ecf20Sopenharmony_ci ufs_put_locked_page(lastpage); 11138c2ecf20Sopenharmony_ciout: 11148c2ecf20Sopenharmony_ci return err; 11158c2ecf20Sopenharmony_ci} 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_cistatic void ufs_truncate_blocks(struct inode *inode) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci struct ufs_inode_info *ufsi = UFS_I(inode); 11208c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 11218c2ecf20Sopenharmony_ci struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 11228c2ecf20Sopenharmony_ci unsigned offsets[4]; 11238c2ecf20Sopenharmony_ci int depth; 11248c2ecf20Sopenharmony_ci int depth2; 11258c2ecf20Sopenharmony_ci unsigned i; 11268c2ecf20Sopenharmony_ci struct ufs_buffer_head *ubh[3]; 11278c2ecf20Sopenharmony_ci void *p; 11288c2ecf20Sopenharmony_ci u64 block; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci if (inode->i_size) { 11318c2ecf20Sopenharmony_ci sector_t last = (inode->i_size - 1) >> uspi->s_bshift; 11328c2ecf20Sopenharmony_ci depth = ufs_block_to_path(inode, last, offsets); 11338c2ecf20Sopenharmony_ci if (!depth) 11348c2ecf20Sopenharmony_ci return; 11358c2ecf20Sopenharmony_ci } else { 11368c2ecf20Sopenharmony_ci depth = 1; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci for (depth2 = depth - 1; depth2; depth2--) 11408c2ecf20Sopenharmony_ci if (offsets[depth2] != uspi->s_apb - 1) 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci mutex_lock(&ufsi->truncate_mutex); 11448c2ecf20Sopenharmony_ci if (depth == 1) { 11458c2ecf20Sopenharmony_ci ufs_trunc_direct(inode); 11468c2ecf20Sopenharmony_ci offsets[0] = UFS_IND_BLOCK; 11478c2ecf20Sopenharmony_ci } else { 11488c2ecf20Sopenharmony_ci /* get the blocks that should be partially emptied */ 11498c2ecf20Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]++); 11508c2ecf20Sopenharmony_ci for (i = 0; i < depth2; i++) { 11518c2ecf20Sopenharmony_ci block = ufs_data_ptr_to_cpu(sb, p); 11528c2ecf20Sopenharmony_ci if (!block) 11538c2ecf20Sopenharmony_ci break; 11548c2ecf20Sopenharmony_ci ubh[i] = ubh_bread(sb, block, uspi->s_bsize); 11558c2ecf20Sopenharmony_ci if (!ubh[i]) { 11568c2ecf20Sopenharmony_ci write_seqlock(&ufsi->meta_lock); 11578c2ecf20Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 11588c2ecf20Sopenharmony_ci write_sequnlock(&ufsi->meta_lock); 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci p = ubh_get_data_ptr(uspi, ubh[i], offsets[i + 1]++); 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci while (i--) 11648c2ecf20Sopenharmony_ci free_branch_tail(inode, offsets[i + 1], ubh[i], depth - i - 1); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) { 11678c2ecf20Sopenharmony_ci p = ufs_get_direct_data_ptr(uspi, ufsi, i); 11688c2ecf20Sopenharmony_ci block = ufs_data_ptr_to_cpu(sb, p); 11698c2ecf20Sopenharmony_ci if (block) { 11708c2ecf20Sopenharmony_ci write_seqlock(&ufsi->meta_lock); 11718c2ecf20Sopenharmony_ci ufs_data_ptr_clear(uspi, p); 11728c2ecf20Sopenharmony_ci write_sequnlock(&ufsi->meta_lock); 11738c2ecf20Sopenharmony_ci free_full_branch(inode, block, i - UFS_IND_BLOCK + 1); 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci read_seqlock_excl(&ufsi->meta_lock); 11778c2ecf20Sopenharmony_ci ufsi->i_lastfrag = DIRECT_FRAGMENT; 11788c2ecf20Sopenharmony_ci read_sequnlock_excl(&ufsi->meta_lock); 11798c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 11808c2ecf20Sopenharmony_ci mutex_unlock(&ufsi->truncate_mutex); 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cistatic int ufs_truncate(struct inode *inode, loff_t size) 11848c2ecf20Sopenharmony_ci{ 11858c2ecf20Sopenharmony_ci int err = 0; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", 11888c2ecf20Sopenharmony_ci inode->i_ino, (unsigned long long)size, 11898c2ecf20Sopenharmony_ci (unsigned long long)i_size_read(inode)); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || 11928c2ecf20Sopenharmony_ci S_ISLNK(inode->i_mode))) 11938c2ecf20Sopenharmony_ci return -EINVAL; 11948c2ecf20Sopenharmony_ci if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) 11958c2ecf20Sopenharmony_ci return -EPERM; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci err = ufs_alloc_lastblock(inode, size); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci if (err) 12008c2ecf20Sopenharmony_ci goto out; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci block_truncate_page(inode->i_mapping, size, ufs_getfrag_block); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci truncate_setsize(inode, size); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci ufs_truncate_blocks(inode); 12078c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_ctime = current_time(inode); 12088c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 12098c2ecf20Sopenharmony_ciout: 12108c2ecf20Sopenharmony_ci UFSD("EXIT: err %d\n", err); 12118c2ecf20Sopenharmony_ci return err; 12128c2ecf20Sopenharmony_ci} 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ciint ufs_setattr(struct dentry *dentry, struct iattr *attr) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 12178c2ecf20Sopenharmony_ci unsigned int ia_valid = attr->ia_valid; 12188c2ecf20Sopenharmony_ci int error; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci error = setattr_prepare(dentry, attr); 12218c2ecf20Sopenharmony_ci if (error) 12228c2ecf20Sopenharmony_ci return error; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) { 12258c2ecf20Sopenharmony_ci error = ufs_truncate(inode, attr->ia_size); 12268c2ecf20Sopenharmony_ci if (error) 12278c2ecf20Sopenharmony_ci return error; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci setattr_copy(inode, attr); 12318c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 12328c2ecf20Sopenharmony_ci return 0; 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ciconst struct inode_operations ufs_file_inode_operations = { 12368c2ecf20Sopenharmony_ci .setattr = ufs_setattr, 12378c2ecf20Sopenharmony_ci}; 1238