11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/ufs/inode.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1998 51da177e4SLinus Torvalds * Daniel Pirkl <daniel.pirkl@email.cz> 61da177e4SLinus Torvalds * Charles University, Faculty of Mathematics and Physics 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * from 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * linux/fs/ext2/inode.c 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Copyright (C) 1992, 1993, 1994, 1995 131da177e4SLinus Torvalds * Remy Card (card@masi.ibp.fr) 141da177e4SLinus Torvalds * Laboratoire MASI - Institut Blaise Pascal 151da177e4SLinus Torvalds * Universite Pierre et Marie Curie (Paris VI) 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * from 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * linux/fs/minix/inode.c 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 241da177e4SLinus Torvalds * Big-endian to little-endian byte-swapping/bitmaps by 251da177e4SLinus Torvalds * David S. Miller (davem@caip.rutgers.edu), 1995 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include <asm/uaccess.h> 291da177e4SLinus Torvalds #include <asm/system.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #include <linux/errno.h> 321da177e4SLinus Torvalds #include <linux/fs.h> 331da177e4SLinus Torvalds #include <linux/ufs_fs.h> 341da177e4SLinus Torvalds #include <linux/time.h> 351da177e4SLinus Torvalds #include <linux/stat.h> 361da177e4SLinus Torvalds #include <linux/string.h> 371da177e4SLinus Torvalds #include <linux/mm.h> 381da177e4SLinus Torvalds #include <linux/smp_lock.h> 391da177e4SLinus Torvalds #include <linux/buffer_head.h> 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds #include "swab.h" 421da177e4SLinus Torvalds #include "util.h" 431da177e4SLinus Torvalds 44138bb68aSAdrian Bunk static u64 ufs_frag_map(struct inode *inode, sector_t frag); 45138bb68aSAdrian Bunk 461da177e4SLinus Torvalds static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4]) 471da177e4SLinus Torvalds { 481da177e4SLinus Torvalds struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; 491da177e4SLinus Torvalds int ptrs = uspi->s_apb; 501da177e4SLinus Torvalds int ptrs_bits = uspi->s_apbshift; 511da177e4SLinus Torvalds const long direct_blocks = UFS_NDADDR, 521da177e4SLinus Torvalds indirect_blocks = ptrs, 531da177e4SLinus Torvalds double_blocks = (1 << (ptrs_bits * 2)); 541da177e4SLinus Torvalds int n = 0; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds 57abf5d15fSEvgeniy Dushistov UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); 581da177e4SLinus Torvalds if (i_block < 0) { 591da177e4SLinus Torvalds ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0"); 601da177e4SLinus Torvalds } else if (i_block < direct_blocks) { 611da177e4SLinus Torvalds offsets[n++] = i_block; 621da177e4SLinus Torvalds } else if ((i_block -= direct_blocks) < indirect_blocks) { 631da177e4SLinus Torvalds offsets[n++] = UFS_IND_BLOCK; 641da177e4SLinus Torvalds offsets[n++] = i_block; 651da177e4SLinus Torvalds } else if ((i_block -= indirect_blocks) < double_blocks) { 661da177e4SLinus Torvalds offsets[n++] = UFS_DIND_BLOCK; 671da177e4SLinus Torvalds offsets[n++] = i_block >> ptrs_bits; 681da177e4SLinus Torvalds offsets[n++] = i_block & (ptrs - 1); 691da177e4SLinus Torvalds } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { 701da177e4SLinus Torvalds offsets[n++] = UFS_TIND_BLOCK; 711da177e4SLinus Torvalds offsets[n++] = i_block >> (ptrs_bits * 2); 721da177e4SLinus Torvalds offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); 731da177e4SLinus Torvalds offsets[n++] = i_block & (ptrs - 1); 741da177e4SLinus Torvalds } else { 751da177e4SLinus Torvalds ufs_warning(inode->i_sb, "ufs_block_to_path", "block > big"); 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds return n; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds /* 811da177e4SLinus Torvalds * Returns the location of the fragment from 821da177e4SLinus Torvalds * the begining of the filesystem. 831da177e4SLinus Torvalds */ 841da177e4SLinus Torvalds 85138bb68aSAdrian Bunk static u64 ufs_frag_map(struct inode *inode, sector_t frag) 861da177e4SLinus Torvalds { 871da177e4SLinus Torvalds struct ufs_inode_info *ufsi = UFS_I(inode); 881da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 891da177e4SLinus Torvalds struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 901da177e4SLinus Torvalds u64 mask = (u64) uspi->s_apbmask>>uspi->s_fpbshift; 911da177e4SLinus Torvalds int shift = uspi->s_apbshift-uspi->s_fpbshift; 921da177e4SLinus Torvalds sector_t offsets[4], *p; 931da177e4SLinus Torvalds int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets); 941da177e4SLinus Torvalds u64 ret = 0L; 951da177e4SLinus Torvalds __fs32 block; 961da177e4SLinus Torvalds __fs64 u2_block = 0L; 971da177e4SLinus Torvalds unsigned flags = UFS_SB(sb)->s_flags; 981da177e4SLinus Torvalds u64 temp = 0L; 991da177e4SLinus Torvalds 100abf5d15fSEvgeniy Dushistov UFSD(": frag = %llu depth = %d\n", (unsigned long long)frag, depth); 1017256d819SAndrew Morton UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n", 1027256d819SAndrew Morton uspi->s_fpbshift, uspi->s_apbmask, 1037256d819SAndrew Morton (unsigned long long)mask); 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds if (depth == 0) 1061da177e4SLinus Torvalds return 0; 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds p = offsets; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds lock_kernel(); 1111da177e4SLinus Torvalds if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 1121da177e4SLinus Torvalds goto ufs2; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds block = ufsi->i_u1.i_data[*p++]; 1151da177e4SLinus Torvalds if (!block) 1161da177e4SLinus Torvalds goto out; 1171da177e4SLinus Torvalds while (--depth) { 1181da177e4SLinus Torvalds struct buffer_head *bh; 1191da177e4SLinus Torvalds sector_t n = *p++; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds bh = sb_bread(sb, uspi->s_sbbase + fs32_to_cpu(sb, block)+(n>>shift)); 1221da177e4SLinus Torvalds if (!bh) 1231da177e4SLinus Torvalds goto out; 1241da177e4SLinus Torvalds block = ((__fs32 *) bh->b_data)[n & mask]; 1251da177e4SLinus Torvalds brelse (bh); 1261da177e4SLinus Torvalds if (!block) 1271da177e4SLinus Torvalds goto out; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds ret = (u64) (uspi->s_sbbase + fs32_to_cpu(sb, block) + (frag & uspi->s_fpbmask)); 1301da177e4SLinus Torvalds goto out; 1311da177e4SLinus Torvalds ufs2: 1321da177e4SLinus Torvalds u2_block = ufsi->i_u1.u2_i_data[*p++]; 1331da177e4SLinus Torvalds if (!u2_block) 1341da177e4SLinus Torvalds goto out; 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds while (--depth) { 1381da177e4SLinus Torvalds struct buffer_head *bh; 1391da177e4SLinus Torvalds sector_t n = *p++; 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds temp = (u64)(uspi->s_sbbase) + fs64_to_cpu(sb, u2_block); 1431da177e4SLinus Torvalds bh = sb_bread(sb, temp +(u64) (n>>shift)); 1441da177e4SLinus Torvalds if (!bh) 1451da177e4SLinus Torvalds goto out; 1461da177e4SLinus Torvalds u2_block = ((__fs64 *)bh->b_data)[n & mask]; 1471da177e4SLinus Torvalds brelse(bh); 1481da177e4SLinus Torvalds if (!u2_block) 1491da177e4SLinus Torvalds goto out; 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds temp = (u64)uspi->s_sbbase + fs64_to_cpu(sb, u2_block); 1521da177e4SLinus Torvalds ret = temp + (u64) (frag & uspi->s_fpbmask); 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds out: 1551da177e4SLinus Torvalds unlock_kernel(); 1561da177e4SLinus Torvalds return ret; 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds 159022a6dc5SEvgeniy Dushistov static void ufs_clear_frag(struct inode *inode, struct buffer_head *bh) 160c9a27b5dSEvgeniy Dushistov { 161c9a27b5dSEvgeniy Dushistov lock_buffer(bh); 162c9a27b5dSEvgeniy Dushistov memset(bh->b_data, 0, inode->i_sb->s_blocksize); 163c9a27b5dSEvgeniy Dushistov set_buffer_uptodate(bh); 164c9a27b5dSEvgeniy Dushistov mark_buffer_dirty(bh); 165c9a27b5dSEvgeniy Dushistov unlock_buffer(bh); 166c9a27b5dSEvgeniy Dushistov if (IS_SYNC(inode)) 167c9a27b5dSEvgeniy Dushistov sync_dirty_buffer(bh); 168c9a27b5dSEvgeniy Dushistov } 169c9a27b5dSEvgeniy Dushistov 170022a6dc5SEvgeniy Dushistov static struct buffer_head * 171022a6dc5SEvgeniy Dushistov ufs_clear_frags(struct inode *inode, sector_t beg, 172c37336b0SEvgeniy Dushistov unsigned int n, sector_t want) 173022a6dc5SEvgeniy Dushistov { 174c37336b0SEvgeniy Dushistov struct buffer_head *res = NULL, *bh; 175022a6dc5SEvgeniy Dushistov sector_t end = beg + n; 176022a6dc5SEvgeniy Dushistov 177c37336b0SEvgeniy Dushistov for (; beg < end; ++beg) { 178022a6dc5SEvgeniy Dushistov bh = sb_getblk(inode->i_sb, beg); 179022a6dc5SEvgeniy Dushistov ufs_clear_frag(inode, bh); 180c37336b0SEvgeniy Dushistov if (want != beg) 181f3914758SEvgeniy Dushistov brelse(bh); 182c37336b0SEvgeniy Dushistov else 183c37336b0SEvgeniy Dushistov res = bh; 184022a6dc5SEvgeniy Dushistov } 185c37336b0SEvgeniy Dushistov BUG_ON(!res); 186022a6dc5SEvgeniy Dushistov return res; 187022a6dc5SEvgeniy Dushistov } 188022a6dc5SEvgeniy Dushistov 189022a6dc5SEvgeniy Dushistov /** 190022a6dc5SEvgeniy Dushistov * ufs_inode_getfrag() - allocate new fragment(s) 191022a6dc5SEvgeniy Dushistov * @inode - pointer to inode 192022a6dc5SEvgeniy Dushistov * @fragment - number of `fragment' which hold pointer 193022a6dc5SEvgeniy Dushistov * to new allocated fragment(s) 194022a6dc5SEvgeniy Dushistov * @new_fragment - number of new allocated fragment(s) 195022a6dc5SEvgeniy Dushistov * @required - how many fragment(s) we require 196022a6dc5SEvgeniy Dushistov * @err - we set it if something wrong 197022a6dc5SEvgeniy Dushistov * @phys - pointer to where we save physical number of new allocated fragments, 198022a6dc5SEvgeniy Dushistov * NULL if we allocate not data(indirect blocks for example). 199022a6dc5SEvgeniy Dushistov * @new - we set it if we allocate new block 200022a6dc5SEvgeniy Dushistov * @locked_page - for ufs_new_fragments() 201022a6dc5SEvgeniy Dushistov */ 202022a6dc5SEvgeniy Dushistov static struct buffer_head * 203022a6dc5SEvgeniy Dushistov ufs_inode_getfrag(struct inode *inode, unsigned int fragment, 204022a6dc5SEvgeniy Dushistov sector_t new_fragment, unsigned int required, int *err, 2056ef4d6bfSEvgeniy Dushistov long *phys, int *new, struct page *locked_page) 2061da177e4SLinus Torvalds { 2071da177e4SLinus Torvalds struct ufs_inode_info *ufsi = UFS_I(inode); 208022a6dc5SEvgeniy Dushistov struct super_block *sb = inode->i_sb; 209022a6dc5SEvgeniy Dushistov struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 2101da177e4SLinus Torvalds struct buffer_head * result; 2111da177e4SLinus Torvalds unsigned block, blockoff, lastfrag, lastblock, lastblockoff; 2121da177e4SLinus Torvalds unsigned tmp, goal; 2131da177e4SLinus Torvalds __fs32 * p, * p2; 2141da177e4SLinus Torvalds 215022a6dc5SEvgeniy Dushistov UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, required %u, " 216022a6dc5SEvgeniy Dushistov "metadata %d\n", inode->i_ino, fragment, 217022a6dc5SEvgeniy Dushistov (unsigned long long)new_fragment, required, !phys); 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds /* TODO : to be done for write support 2201da177e4SLinus Torvalds if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 2211da177e4SLinus Torvalds goto ufs2; 2221da177e4SLinus Torvalds */ 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds block = ufs_fragstoblks (fragment); 2251da177e4SLinus Torvalds blockoff = ufs_fragnum (fragment); 2261da177e4SLinus Torvalds p = ufsi->i_u1.i_data + block; 2271da177e4SLinus Torvalds goal = 0; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds repeat: 2301da177e4SLinus Torvalds tmp = fs32_to_cpu(sb, *p); 2311da177e4SLinus Torvalds lastfrag = ufsi->i_lastfrag; 2321da177e4SLinus Torvalds if (tmp && fragment < lastfrag) { 233022a6dc5SEvgeniy Dushistov if (!phys) { 2341da177e4SLinus Torvalds result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); 2351da177e4SLinus Torvalds if (tmp == fs32_to_cpu(sb, *p)) { 236abf5d15fSEvgeniy Dushistov UFSD("EXIT, result %u\n", tmp + blockoff); 2371da177e4SLinus Torvalds return result; 2381da177e4SLinus Torvalds } 2391da177e4SLinus Torvalds brelse (result); 2401da177e4SLinus Torvalds goto repeat; 2411da177e4SLinus Torvalds } else { 242c9a27b5dSEvgeniy Dushistov *phys = tmp + blockoff; 2431da177e4SLinus Torvalds return NULL; 2441da177e4SLinus Torvalds } 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds lastblock = ufs_fragstoblks (lastfrag); 2481da177e4SLinus Torvalds lastblockoff = ufs_fragnum (lastfrag); 2491da177e4SLinus Torvalds /* 2501da177e4SLinus Torvalds * We will extend file into new block beyond last allocated block 2511da177e4SLinus Torvalds */ 2521da177e4SLinus Torvalds if (lastblock < block) { 2531da177e4SLinus Torvalds /* 2541da177e4SLinus Torvalds * We must reallocate last allocated block 2551da177e4SLinus Torvalds */ 2561da177e4SLinus Torvalds if (lastblockoff) { 2571da177e4SLinus Torvalds p2 = ufsi->i_u1.i_data + lastblock; 2581da177e4SLinus Torvalds tmp = ufs_new_fragments (inode, p2, lastfrag, 2596ef4d6bfSEvgeniy Dushistov fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, 2606ef4d6bfSEvgeniy Dushistov err, locked_page); 2611da177e4SLinus Torvalds if (!tmp) { 2621da177e4SLinus Torvalds if (lastfrag != ufsi->i_lastfrag) 2631da177e4SLinus Torvalds goto repeat; 2641da177e4SLinus Torvalds else 2651da177e4SLinus Torvalds return NULL; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds lastfrag = ufsi->i_lastfrag; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds } 270c37336b0SEvgeniy Dushistov tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]); 271c37336b0SEvgeniy Dushistov if (tmp) 272c37336b0SEvgeniy Dushistov goal = tmp + uspi->s_fpb; 2731da177e4SLinus Torvalds tmp = ufs_new_fragments (inode, p, fragment - blockoff, 2746ef4d6bfSEvgeniy Dushistov goal, required + blockoff, 2756ef4d6bfSEvgeniy Dushistov err, locked_page); 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds /* 2781da177e4SLinus Torvalds * We will extend last allocated block 2791da177e4SLinus Torvalds */ 2801da177e4SLinus Torvalds else if (lastblock == block) { 2811da177e4SLinus Torvalds tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff), 2826ef4d6bfSEvgeniy Dushistov fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), 2836ef4d6bfSEvgeniy Dushistov err, locked_page); 284c37336b0SEvgeniy Dushistov } else /* (lastblock > block) */ { 2851da177e4SLinus Torvalds /* 2861da177e4SLinus Torvalds * We will allocate new block before last allocated block 2871da177e4SLinus Torvalds */ 288c37336b0SEvgeniy Dushistov if (block) { 289c37336b0SEvgeniy Dushistov tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[block-1]); 290c37336b0SEvgeniy Dushistov if (tmp) 2911da177e4SLinus Torvalds goal = tmp + uspi->s_fpb; 292c37336b0SEvgeniy Dushistov } 2931da177e4SLinus Torvalds tmp = ufs_new_fragments(inode, p, fragment - blockoff, 2946ef4d6bfSEvgeniy Dushistov goal, uspi->s_fpb, err, locked_page); 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds if (!tmp) { 2971da177e4SLinus Torvalds if ((!blockoff && *p) || 2981da177e4SLinus Torvalds (blockoff && lastfrag != ufsi->i_lastfrag)) 2991da177e4SLinus Torvalds goto repeat; 3001da177e4SLinus Torvalds *err = -ENOSPC; 3011da177e4SLinus Torvalds return NULL; 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 304022a6dc5SEvgeniy Dushistov if (!phys) { 305c37336b0SEvgeniy Dushistov result = ufs_clear_frags(inode, tmp, required, tmp + blockoff); 3061da177e4SLinus Torvalds } else { 307c9a27b5dSEvgeniy Dushistov *phys = tmp + blockoff; 3081da177e4SLinus Torvalds result = NULL; 3091da177e4SLinus Torvalds *err = 0; 3101da177e4SLinus Torvalds *new = 1; 3111da177e4SLinus Torvalds } 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 3141da177e4SLinus Torvalds if (IS_SYNC(inode)) 3151da177e4SLinus Torvalds ufs_sync_inode (inode); 3161da177e4SLinus Torvalds mark_inode_dirty(inode); 317abf5d15fSEvgeniy Dushistov UFSD("EXIT, result %u\n", tmp + blockoff); 3181da177e4SLinus Torvalds return result; 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds /* This part : To be implemented .... 3211da177e4SLinus Torvalds Required only for writing, not required for READ-ONLY. 3221da177e4SLinus Torvalds ufs2: 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds u2_block = ufs_fragstoblks(fragment); 3251da177e4SLinus Torvalds u2_blockoff = ufs_fragnum(fragment); 3261da177e4SLinus Torvalds p = ufsi->i_u1.u2_i_data + block; 3271da177e4SLinus Torvalds goal = 0; 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds repeat2: 3301da177e4SLinus Torvalds tmp = fs32_to_cpu(sb, *p); 3311da177e4SLinus Torvalds lastfrag = ufsi->i_lastfrag; 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds */ 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds 336022a6dc5SEvgeniy Dushistov /** 337022a6dc5SEvgeniy Dushistov * ufs_inode_getblock() - allocate new block 338022a6dc5SEvgeniy Dushistov * @inode - pointer to inode 339022a6dc5SEvgeniy Dushistov * @bh - pointer to block which hold "pointer" to new allocated block 340022a6dc5SEvgeniy Dushistov * @fragment - number of `fragment' which hold pointer 341022a6dc5SEvgeniy Dushistov * to new allocated block 342022a6dc5SEvgeniy Dushistov * @new_fragment - number of new allocated fragment 343022a6dc5SEvgeniy Dushistov * (block will hold this fragment and also uspi->s_fpb-1) 344022a6dc5SEvgeniy Dushistov * @err - see ufs_inode_getfrag() 345022a6dc5SEvgeniy Dushistov * @phys - see ufs_inode_getfrag() 346022a6dc5SEvgeniy Dushistov * @new - see ufs_inode_getfrag() 347022a6dc5SEvgeniy Dushistov * @locked_page - see ufs_inode_getfrag() 348022a6dc5SEvgeniy Dushistov */ 349022a6dc5SEvgeniy Dushistov static struct buffer_head * 350022a6dc5SEvgeniy Dushistov ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, 351022a6dc5SEvgeniy Dushistov unsigned int fragment, sector_t new_fragment, int *err, 3526ef4d6bfSEvgeniy Dushistov long *phys, int *new, struct page *locked_page) 3531da177e4SLinus Torvalds { 354022a6dc5SEvgeniy Dushistov struct super_block *sb = inode->i_sb; 355022a6dc5SEvgeniy Dushistov struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; 3561da177e4SLinus Torvalds struct buffer_head * result; 3571da177e4SLinus Torvalds unsigned tmp, goal, block, blockoff; 3581da177e4SLinus Torvalds __fs32 * p; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds block = ufs_fragstoblks (fragment); 3611da177e4SLinus Torvalds blockoff = ufs_fragnum (fragment); 3621da177e4SLinus Torvalds 363022a6dc5SEvgeniy Dushistov UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, metadata %d\n", 364022a6dc5SEvgeniy Dushistov inode->i_ino, fragment, (unsigned long long)new_fragment, !phys); 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds result = NULL; 3671da177e4SLinus Torvalds if (!bh) 3681da177e4SLinus Torvalds goto out; 3691da177e4SLinus Torvalds if (!buffer_uptodate(bh)) { 3701da177e4SLinus Torvalds ll_rw_block (READ, 1, &bh); 3711da177e4SLinus Torvalds wait_on_buffer (bh); 3721da177e4SLinus Torvalds if (!buffer_uptodate(bh)) 3731da177e4SLinus Torvalds goto out; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds p = (__fs32 *) bh->b_data + block; 3771da177e4SLinus Torvalds repeat: 3781da177e4SLinus Torvalds tmp = fs32_to_cpu(sb, *p); 3791da177e4SLinus Torvalds if (tmp) { 380022a6dc5SEvgeniy Dushistov if (!phys) { 3811da177e4SLinus Torvalds result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); 3821da177e4SLinus Torvalds if (tmp == fs32_to_cpu(sb, *p)) 3831da177e4SLinus Torvalds goto out; 3841da177e4SLinus Torvalds brelse (result); 3851da177e4SLinus Torvalds goto repeat; 3861da177e4SLinus Torvalds } else { 387c9a27b5dSEvgeniy Dushistov *phys = tmp + blockoff; 3881da177e4SLinus Torvalds goto out; 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 392c37336b0SEvgeniy Dushistov if (block && (tmp = fs32_to_cpu(sb, ((__fs32*)bh->b_data)[block-1]))) 3931da177e4SLinus Torvalds goal = tmp + uspi->s_fpb; 3941da177e4SLinus Torvalds else 3951da177e4SLinus Torvalds goal = bh->b_blocknr + uspi->s_fpb; 3966ef4d6bfSEvgeniy Dushistov tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, 3976ef4d6bfSEvgeniy Dushistov uspi->s_fpb, err, locked_page); 3981da177e4SLinus Torvalds if (!tmp) { 3991da177e4SLinus Torvalds if (fs32_to_cpu(sb, *p)) 4001da177e4SLinus Torvalds goto repeat; 4011da177e4SLinus Torvalds goto out; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds 404c9a27b5dSEvgeniy Dushistov 405022a6dc5SEvgeniy Dushistov if (!phys) { 406c37336b0SEvgeniy Dushistov result = ufs_clear_frags(inode, tmp, uspi->s_fpb, 407c37336b0SEvgeniy Dushistov tmp + blockoff); 4081da177e4SLinus Torvalds } else { 409c9a27b5dSEvgeniy Dushistov *phys = tmp + blockoff; 4101da177e4SLinus Torvalds *new = 1; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds mark_buffer_dirty(bh); 4141da177e4SLinus Torvalds if (IS_SYNC(inode)) 4151da177e4SLinus Torvalds sync_dirty_buffer(bh); 4161da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 4171da177e4SLinus Torvalds mark_inode_dirty(inode); 418abf5d15fSEvgeniy Dushistov UFSD("result %u\n", tmp + blockoff); 4191da177e4SLinus Torvalds out: 4201da177e4SLinus Torvalds brelse (bh); 421abf5d15fSEvgeniy Dushistov UFSD("EXIT\n"); 4221da177e4SLinus Torvalds return result; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 425022a6dc5SEvgeniy Dushistov /** 426022a6dc5SEvgeniy Dushistov * ufs_getfrag_bloc() - `get_block_t' function, interface between UFS and 427022a6dc5SEvgeniy Dushistov * readpage, writepage and so on 4281da177e4SLinus Torvalds */ 4291da177e4SLinus Torvalds 43009114eb8SEvgeniy Dushistov int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) 4311da177e4SLinus Torvalds { 4321da177e4SLinus Torvalds struct super_block * sb = inode->i_sb; 4331da177e4SLinus Torvalds struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi; 4341da177e4SLinus Torvalds struct buffer_head * bh; 4351da177e4SLinus Torvalds int ret, err, new; 4361da177e4SLinus Torvalds unsigned long ptr,phys; 4371da177e4SLinus Torvalds u64 phys64 = 0; 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds if (!create) { 4401da177e4SLinus Torvalds phys64 = ufs_frag_map(inode, fragment); 4417256d819SAndrew Morton UFSD("phys64 = %llu\n", (unsigned long long)phys64); 4421da177e4SLinus Torvalds if (phys64) 4431da177e4SLinus Torvalds map_bh(bh_result, sb, phys64); 4441da177e4SLinus Torvalds return 0; 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds /* This code entered only while writing ....? */ 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds err = -EIO; 4501da177e4SLinus Torvalds new = 0; 4511da177e4SLinus Torvalds ret = 0; 4521da177e4SLinus Torvalds bh = NULL; 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds lock_kernel(); 4551da177e4SLinus Torvalds 456abf5d15fSEvgeniy Dushistov UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); 4571da177e4SLinus Torvalds if (fragment < 0) 4581da177e4SLinus Torvalds goto abort_negative; 4591da177e4SLinus Torvalds if (fragment > 4601da177e4SLinus Torvalds ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) 4611da177e4SLinus Torvalds << uspi->s_fpbshift)) 4621da177e4SLinus Torvalds goto abort_too_big; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds err = 0; 4651da177e4SLinus Torvalds ptr = fragment; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds /* 4681da177e4SLinus Torvalds * ok, these macros clean the logic up a bit and make 4691da177e4SLinus Torvalds * it much more readable: 4701da177e4SLinus Torvalds */ 4711da177e4SLinus Torvalds #define GET_INODE_DATABLOCK(x) \ 472022a6dc5SEvgeniy Dushistov ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new, bh_result->b_page) 4731da177e4SLinus Torvalds #define GET_INODE_PTR(x) \ 474022a6dc5SEvgeniy Dushistov ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page) 4751da177e4SLinus Torvalds #define GET_INDIRECT_DATABLOCK(x) \ 476022a6dc5SEvgeniy Dushistov ufs_inode_getblock(inode, bh, x, fragment, \ 477022a6dc5SEvgeniy Dushistov &err, &phys, &new, bh_result->b_page); 4781da177e4SLinus Torvalds #define GET_INDIRECT_PTR(x) \ 479022a6dc5SEvgeniy Dushistov ufs_inode_getblock(inode, bh, x, fragment, \ 480022a6dc5SEvgeniy Dushistov &err, NULL, NULL, bh_result->b_page); 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds if (ptr < UFS_NDIR_FRAGMENT) { 4831da177e4SLinus Torvalds bh = GET_INODE_DATABLOCK(ptr); 4841da177e4SLinus Torvalds goto out; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds ptr -= UFS_NDIR_FRAGMENT; 4871da177e4SLinus Torvalds if (ptr < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) { 4881da177e4SLinus Torvalds bh = GET_INODE_PTR(UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift)); 4891da177e4SLinus Torvalds goto get_indirect; 4901da177e4SLinus Torvalds } 4911da177e4SLinus Torvalds ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift); 4921da177e4SLinus Torvalds if (ptr < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) { 4931da177e4SLinus Torvalds bh = GET_INODE_PTR(UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift)); 4941da177e4SLinus Torvalds goto get_double; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift); 4971da177e4SLinus Torvalds bh = GET_INODE_PTR(UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift)); 4981da177e4SLinus Torvalds bh = GET_INDIRECT_PTR((ptr >> uspi->s_2apbshift) & uspi->s_apbmask); 4991da177e4SLinus Torvalds get_double: 5001da177e4SLinus Torvalds bh = GET_INDIRECT_PTR((ptr >> uspi->s_apbshift) & uspi->s_apbmask); 5011da177e4SLinus Torvalds get_indirect: 5021da177e4SLinus Torvalds bh = GET_INDIRECT_DATABLOCK(ptr & uspi->s_apbmask); 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds #undef GET_INODE_DATABLOCK 5051da177e4SLinus Torvalds #undef GET_INODE_PTR 5061da177e4SLinus Torvalds #undef GET_INDIRECT_DATABLOCK 5071da177e4SLinus Torvalds #undef GET_INDIRECT_PTR 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds out: 5101da177e4SLinus Torvalds if (err) 5111da177e4SLinus Torvalds goto abort; 5121da177e4SLinus Torvalds if (new) 5131da177e4SLinus Torvalds set_buffer_new(bh_result); 5141da177e4SLinus Torvalds map_bh(bh_result, sb, phys); 5151da177e4SLinus Torvalds abort: 5161da177e4SLinus Torvalds unlock_kernel(); 5171da177e4SLinus Torvalds return err; 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds abort_negative: 5201da177e4SLinus Torvalds ufs_warning(sb, "ufs_get_block", "block < 0"); 5211da177e4SLinus Torvalds goto abort; 5221da177e4SLinus Torvalds 5231da177e4SLinus Torvalds abort_too_big: 5241da177e4SLinus Torvalds ufs_warning(sb, "ufs_get_block", "block > big"); 5251da177e4SLinus Torvalds goto abort; 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds 528138bb68aSAdrian Bunk static struct buffer_head *ufs_getfrag(struct inode *inode, 529138bb68aSAdrian Bunk unsigned int fragment, 5301da177e4SLinus Torvalds int create, int *err) 5311da177e4SLinus Torvalds { 5321da177e4SLinus Torvalds struct buffer_head dummy; 5331da177e4SLinus Torvalds int error; 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds dummy.b_state = 0; 5361da177e4SLinus Torvalds dummy.b_blocknr = -1000; 5371da177e4SLinus Torvalds error = ufs_getfrag_block(inode, fragment, &dummy, create); 5381da177e4SLinus Torvalds *err = error; 5391da177e4SLinus Torvalds if (!error && buffer_mapped(&dummy)) { 5401da177e4SLinus Torvalds struct buffer_head *bh; 5411da177e4SLinus Torvalds bh = sb_getblk(inode->i_sb, dummy.b_blocknr); 5421da177e4SLinus Torvalds if (buffer_new(&dummy)) { 5431da177e4SLinus Torvalds memset(bh->b_data, 0, inode->i_sb->s_blocksize); 5441da177e4SLinus Torvalds set_buffer_uptodate(bh); 5451da177e4SLinus Torvalds mark_buffer_dirty(bh); 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds return bh; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds return NULL; 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment, 5531da177e4SLinus Torvalds int create, int * err) 5541da177e4SLinus Torvalds { 5551da177e4SLinus Torvalds struct buffer_head * bh; 5561da177e4SLinus Torvalds 557abf5d15fSEvgeniy Dushistov UFSD("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment); 5581da177e4SLinus Torvalds bh = ufs_getfrag (inode, fragment, create, err); 5591da177e4SLinus Torvalds if (!bh || buffer_uptodate(bh)) 5601da177e4SLinus Torvalds return bh; 5611da177e4SLinus Torvalds ll_rw_block (READ, 1, &bh); 5621da177e4SLinus Torvalds wait_on_buffer (bh); 5631da177e4SLinus Torvalds if (buffer_uptodate(bh)) 5641da177e4SLinus Torvalds return bh; 5651da177e4SLinus Torvalds brelse (bh); 5661da177e4SLinus Torvalds *err = -EIO; 5671da177e4SLinus Torvalds return NULL; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds static int ufs_writepage(struct page *page, struct writeback_control *wbc) 5711da177e4SLinus Torvalds { 5721da177e4SLinus Torvalds return block_write_full_page(page,ufs_getfrag_block,wbc); 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds static int ufs_readpage(struct file *file, struct page *page) 5751da177e4SLinus Torvalds { 5761da177e4SLinus Torvalds return block_read_full_page(page,ufs_getfrag_block); 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds static int ufs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) 5791da177e4SLinus Torvalds { 5801da177e4SLinus Torvalds return block_prepare_write(page,from,to,ufs_getfrag_block); 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds static sector_t ufs_bmap(struct address_space *mapping, sector_t block) 5831da177e4SLinus Torvalds { 5841da177e4SLinus Torvalds return generic_block_bmap(mapping,block,ufs_getfrag_block); 5851da177e4SLinus Torvalds } 586f5e54d6eSChristoph Hellwig const struct address_space_operations ufs_aops = { 5871da177e4SLinus Torvalds .readpage = ufs_readpage, 5881da177e4SLinus Torvalds .writepage = ufs_writepage, 5891da177e4SLinus Torvalds .sync_page = block_sync_page, 5901da177e4SLinus Torvalds .prepare_write = ufs_prepare_write, 5911da177e4SLinus Torvalds .commit_write = generic_commit_write, 5921da177e4SLinus Torvalds .bmap = ufs_bmap 5931da177e4SLinus Torvalds }; 5941da177e4SLinus Torvalds 595826843a3SEvgeniy Dushistov static void ufs_set_inode_ops(struct inode *inode) 596826843a3SEvgeniy Dushistov { 597826843a3SEvgeniy Dushistov if (S_ISREG(inode->i_mode)) { 598826843a3SEvgeniy Dushistov inode->i_op = &ufs_file_inode_operations; 599826843a3SEvgeniy Dushistov inode->i_fop = &ufs_file_operations; 600826843a3SEvgeniy Dushistov inode->i_mapping->a_ops = &ufs_aops; 601826843a3SEvgeniy Dushistov } else if (S_ISDIR(inode->i_mode)) { 602826843a3SEvgeniy Dushistov inode->i_op = &ufs_dir_inode_operations; 603826843a3SEvgeniy Dushistov inode->i_fop = &ufs_dir_operations; 604826843a3SEvgeniy Dushistov inode->i_mapping->a_ops = &ufs_aops; 605826843a3SEvgeniy Dushistov } else if (S_ISLNK(inode->i_mode)) { 606826843a3SEvgeniy Dushistov if (!inode->i_blocks) 607826843a3SEvgeniy Dushistov inode->i_op = &ufs_fast_symlink_inode_operations; 608826843a3SEvgeniy Dushistov else { 609826843a3SEvgeniy Dushistov inode->i_op = &page_symlink_inode_operations; 610826843a3SEvgeniy Dushistov inode->i_mapping->a_ops = &ufs_aops; 611826843a3SEvgeniy Dushistov } 612826843a3SEvgeniy Dushistov } else 613826843a3SEvgeniy Dushistov init_special_inode(inode, inode->i_mode, 614826843a3SEvgeniy Dushistov ufs_get_inode_dev(inode->i_sb, UFS_I(inode))); 615826843a3SEvgeniy Dushistov } 616826843a3SEvgeniy Dushistov 61705f225dcSEvgeniy Dushistov static void ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) 6181da177e4SLinus Torvalds { 6191da177e4SLinus Torvalds struct ufs_inode_info *ufsi = UFS_I(inode); 62005f225dcSEvgeniy Dushistov struct super_block *sb = inode->i_sb; 6211da177e4SLinus Torvalds mode_t mode; 6221da177e4SLinus Torvalds unsigned i; 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds /* 6251da177e4SLinus Torvalds * Copy data to the in-core inode. 6261da177e4SLinus Torvalds */ 6271da177e4SLinus Torvalds inode->i_mode = mode = fs16_to_cpu(sb, ufs_inode->ui_mode); 6281da177e4SLinus Torvalds inode->i_nlink = fs16_to_cpu(sb, ufs_inode->ui_nlink); 6291da177e4SLinus Torvalds if (inode->i_nlink == 0) 6301da177e4SLinus Torvalds ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino); 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds /* 6331da177e4SLinus Torvalds * Linux now has 32-bit uid and gid, so we can support EFT. 6341da177e4SLinus Torvalds */ 6351da177e4SLinus Torvalds inode->i_uid = ufs_get_inode_uid(sb, ufs_inode); 6361da177e4SLinus Torvalds inode->i_gid = ufs_get_inode_gid(sb, ufs_inode); 6371da177e4SLinus Torvalds 6381da177e4SLinus Torvalds inode->i_size = fs64_to_cpu(sb, ufs_inode->ui_size); 6391da177e4SLinus Torvalds inode->i_atime.tv_sec = fs32_to_cpu(sb, ufs_inode->ui_atime.tv_sec); 6401da177e4SLinus Torvalds inode->i_ctime.tv_sec = fs32_to_cpu(sb, ufs_inode->ui_ctime.tv_sec); 6411da177e4SLinus Torvalds inode->i_mtime.tv_sec = fs32_to_cpu(sb, ufs_inode->ui_mtime.tv_sec); 6421da177e4SLinus Torvalds inode->i_mtime.tv_nsec = 0; 6431da177e4SLinus Torvalds inode->i_atime.tv_nsec = 0; 6441da177e4SLinus Torvalds inode->i_ctime.tv_nsec = 0; 6451da177e4SLinus Torvalds inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks); 6461da177e4SLinus Torvalds ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags); 6471da177e4SLinus Torvalds ufsi->i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen); 6481da177e4SLinus Torvalds ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); 6491da177e4SLinus Torvalds ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); 65005f225dcSEvgeniy Dushistov 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { 6531da177e4SLinus Torvalds for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) 6541da177e4SLinus Torvalds ufsi->i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i]; 655dd187a26SEvgeniy Dushistov } else { 6561da177e4SLinus Torvalds for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) 6571da177e4SLinus Torvalds ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i]; 6581da177e4SLinus Torvalds } 65905f225dcSEvgeniy Dushistov } 6601da177e4SLinus Torvalds 66105f225dcSEvgeniy Dushistov static void ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) 66205f225dcSEvgeniy Dushistov { 66305f225dcSEvgeniy Dushistov struct ufs_inode_info *ufsi = UFS_I(inode); 66405f225dcSEvgeniy Dushistov struct super_block *sb = inode->i_sb; 66505f225dcSEvgeniy Dushistov mode_t mode; 66605f225dcSEvgeniy Dushistov unsigned i; 6671da177e4SLinus Torvalds 668abf5d15fSEvgeniy Dushistov UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino); 6691da177e4SLinus Torvalds /* 6701da177e4SLinus Torvalds * Copy data to the in-core inode. 6711da177e4SLinus Torvalds */ 6721da177e4SLinus Torvalds inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode); 6731da177e4SLinus Torvalds inode->i_nlink = fs16_to_cpu(sb, ufs2_inode->ui_nlink); 6741da177e4SLinus Torvalds if (inode->i_nlink == 0) 6751da177e4SLinus Torvalds ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino); 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds /* 6781da177e4SLinus Torvalds * Linux now has 32-bit uid and gid, so we can support EFT. 6791da177e4SLinus Torvalds */ 6801da177e4SLinus Torvalds inode->i_uid = fs32_to_cpu(sb, ufs2_inode->ui_uid); 6811da177e4SLinus Torvalds inode->i_gid = fs32_to_cpu(sb, ufs2_inode->ui_gid); 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size); 6841da177e4SLinus Torvalds inode->i_atime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_atime.tv_sec); 6851da177e4SLinus Torvalds inode->i_ctime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_ctime.tv_sec); 6861da177e4SLinus Torvalds inode->i_mtime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_mtime.tv_sec); 6871da177e4SLinus Torvalds inode->i_mtime.tv_nsec = 0; 6881da177e4SLinus Torvalds inode->i_atime.tv_nsec = 0; 6891da177e4SLinus Torvalds inode->i_ctime.tv_nsec = 0; 6901da177e4SLinus Torvalds inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks); 6911da177e4SLinus Torvalds ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags); 6921da177e4SLinus Torvalds ufsi->i_gen = fs32_to_cpu(sb, ufs2_inode->ui_gen); 6931da177e4SLinus Torvalds /* 6941da177e4SLinus Torvalds ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); 6951da177e4SLinus Torvalds ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); 6961da177e4SLinus Torvalds */ 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { 6991da177e4SLinus Torvalds for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) 7001da177e4SLinus Torvalds ufsi->i_u1.u2_i_data[i] = 7011da177e4SLinus Torvalds ufs2_inode->ui_u2.ui_addr.ui_db[i]; 70205f225dcSEvgeniy Dushistov } else { 7031da177e4SLinus Torvalds for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) 7041da177e4SLinus Torvalds ufsi->i_u1.i_symlink[i] = ufs2_inode->ui_u2.ui_symlink[i]; 7051da177e4SLinus Torvalds } 70605f225dcSEvgeniy Dushistov } 70705f225dcSEvgeniy Dushistov 70805f225dcSEvgeniy Dushistov void ufs_read_inode(struct inode * inode) 70905f225dcSEvgeniy Dushistov { 71005f225dcSEvgeniy Dushistov struct ufs_inode_info *ufsi = UFS_I(inode); 71105f225dcSEvgeniy Dushistov struct super_block * sb; 71205f225dcSEvgeniy Dushistov struct ufs_sb_private_info * uspi; 71305f225dcSEvgeniy Dushistov struct buffer_head * bh; 71405f225dcSEvgeniy Dushistov 71505f225dcSEvgeniy Dushistov UFSD("ENTER, ino %lu\n", inode->i_ino); 71605f225dcSEvgeniy Dushistov 71705f225dcSEvgeniy Dushistov sb = inode->i_sb; 71805f225dcSEvgeniy Dushistov uspi = UFS_SB(sb)->s_uspi; 71905f225dcSEvgeniy Dushistov 72005f225dcSEvgeniy Dushistov if (inode->i_ino < UFS_ROOTINO || 72105f225dcSEvgeniy Dushistov inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { 72205f225dcSEvgeniy Dushistov ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n", 72305f225dcSEvgeniy Dushistov inode->i_ino); 72405f225dcSEvgeniy Dushistov goto bad_inode; 72505f225dcSEvgeniy Dushistov } 72605f225dcSEvgeniy Dushistov 72705f225dcSEvgeniy Dushistov bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino)); 72805f225dcSEvgeniy Dushistov if (!bh) { 72905f225dcSEvgeniy Dushistov ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n", 73005f225dcSEvgeniy Dushistov inode->i_ino); 73105f225dcSEvgeniy Dushistov goto bad_inode; 73205f225dcSEvgeniy Dushistov } 73305f225dcSEvgeniy Dushistov if ((UFS_SB(sb)->s_flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { 73405f225dcSEvgeniy Dushistov struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data; 73505f225dcSEvgeniy Dushistov 73605f225dcSEvgeniy Dushistov ufs2_read_inode(inode, 73705f225dcSEvgeniy Dushistov ufs2_inode + ufs_inotofsbo(inode->i_ino)); 73805f225dcSEvgeniy Dushistov } else { 73905f225dcSEvgeniy Dushistov struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data; 74005f225dcSEvgeniy Dushistov 74105f225dcSEvgeniy Dushistov ufs1_read_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino)); 74205f225dcSEvgeniy Dushistov } 74305f225dcSEvgeniy Dushistov 74405f225dcSEvgeniy Dushistov inode->i_blksize = PAGE_SIZE;/*This is the optimal IO size (for stat)*/ 74505f225dcSEvgeniy Dushistov inode->i_version++; 74605f225dcSEvgeniy Dushistov ufsi->i_lastfrag = 74705f225dcSEvgeniy Dushistov (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift; 74805f225dcSEvgeniy Dushistov ufsi->i_dir_start_lookup = 0; 7491da177e4SLinus Torvalds ufsi->i_osync = 0; 7501da177e4SLinus Torvalds 751826843a3SEvgeniy Dushistov ufs_set_inode_ops(inode); 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds brelse(bh); 7541da177e4SLinus Torvalds 755abf5d15fSEvgeniy Dushistov UFSD("EXIT\n"); 7561da177e4SLinus Torvalds return; 75705f225dcSEvgeniy Dushistov 75805f225dcSEvgeniy Dushistov bad_inode: 75905f225dcSEvgeniy Dushistov make_bad_inode(inode); 7601da177e4SLinus Torvalds } 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds static int ufs_update_inode(struct inode * inode, int do_sync) 7631da177e4SLinus Torvalds { 7641da177e4SLinus Torvalds struct ufs_inode_info *ufsi = UFS_I(inode); 7651da177e4SLinus Torvalds struct super_block * sb; 7661da177e4SLinus Torvalds struct ufs_sb_private_info * uspi; 7671da177e4SLinus Torvalds struct buffer_head * bh; 7681da177e4SLinus Torvalds struct ufs_inode * ufs_inode; 7691da177e4SLinus Torvalds unsigned i; 7701da177e4SLinus Torvalds unsigned flags; 7711da177e4SLinus Torvalds 772abf5d15fSEvgeniy Dushistov UFSD("ENTER, ino %lu\n", inode->i_ino); 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds sb = inode->i_sb; 7751da177e4SLinus Torvalds uspi = UFS_SB(sb)->s_uspi; 7761da177e4SLinus Torvalds flags = UFS_SB(sb)->s_flags; 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds if (inode->i_ino < UFS_ROOTINO || 7791da177e4SLinus Torvalds inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { 7801da177e4SLinus Torvalds ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); 7811da177e4SLinus Torvalds return -1; 7821da177e4SLinus Torvalds } 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds bh = sb_bread(sb, ufs_inotofsba(inode->i_ino)); 7851da177e4SLinus Torvalds if (!bh) { 7861da177e4SLinus Torvalds ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); 7871da177e4SLinus Torvalds return -1; 7881da177e4SLinus Torvalds } 7891da177e4SLinus Torvalds ufs_inode = (struct ufs_inode *) (bh->b_data + ufs_inotofsbo(inode->i_ino) * sizeof(struct ufs_inode)); 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); 7921da177e4SLinus Torvalds ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds ufs_set_inode_uid(sb, ufs_inode, inode->i_uid); 7951da177e4SLinus Torvalds ufs_set_inode_gid(sb, ufs_inode, inode->i_gid); 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); 7981da177e4SLinus Torvalds ufs_inode->ui_atime.tv_sec = cpu_to_fs32(sb, inode->i_atime.tv_sec); 7991da177e4SLinus Torvalds ufs_inode->ui_atime.tv_usec = 0; 8001da177e4SLinus Torvalds ufs_inode->ui_ctime.tv_sec = cpu_to_fs32(sb, inode->i_ctime.tv_sec); 8011da177e4SLinus Torvalds ufs_inode->ui_ctime.tv_usec = 0; 8021da177e4SLinus Torvalds ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, inode->i_mtime.tv_sec); 8031da177e4SLinus Torvalds ufs_inode->ui_mtime.tv_usec = 0; 8041da177e4SLinus Torvalds ufs_inode->ui_blocks = cpu_to_fs32(sb, inode->i_blocks); 8051da177e4SLinus Torvalds ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); 8061da177e4SLinus Torvalds ufs_inode->ui_gen = cpu_to_fs32(sb, ufsi->i_gen); 8071da177e4SLinus Torvalds 8081da177e4SLinus Torvalds if ((flags & UFS_UID_MASK) == UFS_UID_EFT) { 8091da177e4SLinus Torvalds ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, ufsi->i_shadow); 8101da177e4SLinus Torvalds ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, ufsi->i_oeftflag); 8111da177e4SLinus Torvalds } 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { 8141da177e4SLinus Torvalds /* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ 8151da177e4SLinus Torvalds ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.i_data[0]; 8161da177e4SLinus Torvalds } else if (inode->i_blocks) { 8171da177e4SLinus Torvalds for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) 8181da177e4SLinus Torvalds ufs_inode->ui_u2.ui_addr.ui_db[i] = ufsi->i_u1.i_data[i]; 8191da177e4SLinus Torvalds } 8201da177e4SLinus Torvalds else { 8211da177e4SLinus Torvalds for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) 8221da177e4SLinus Torvalds ufs_inode->ui_u2.ui_symlink[i] = ufsi->i_u1.i_symlink[i]; 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds 8251da177e4SLinus Torvalds if (!inode->i_nlink) 8261da177e4SLinus Torvalds memset (ufs_inode, 0, sizeof(struct ufs_inode)); 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds mark_buffer_dirty(bh); 8291da177e4SLinus Torvalds if (do_sync) 8301da177e4SLinus Torvalds sync_dirty_buffer(bh); 8311da177e4SLinus Torvalds brelse (bh); 8321da177e4SLinus Torvalds 833abf5d15fSEvgeniy Dushistov UFSD("EXIT\n"); 8341da177e4SLinus Torvalds return 0; 8351da177e4SLinus Torvalds } 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds int ufs_write_inode (struct inode * inode, int wait) 8381da177e4SLinus Torvalds { 8391da177e4SLinus Torvalds int ret; 8401da177e4SLinus Torvalds lock_kernel(); 8411da177e4SLinus Torvalds ret = ufs_update_inode (inode, wait); 8421da177e4SLinus Torvalds unlock_kernel(); 8431da177e4SLinus Torvalds return ret; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds int ufs_sync_inode (struct inode *inode) 8471da177e4SLinus Torvalds { 8481da177e4SLinus Torvalds return ufs_update_inode (inode, 1); 8491da177e4SLinus Torvalds } 8501da177e4SLinus Torvalds 8511da177e4SLinus Torvalds void ufs_delete_inode (struct inode * inode) 8521da177e4SLinus Torvalds { 85310e5dce0SEvgeniy Dushistov loff_t old_i_size; 85410e5dce0SEvgeniy Dushistov 855fef26658SMark Fasheh truncate_inode_pages(&inode->i_data, 0); 8561da177e4SLinus Torvalds /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ 8571da177e4SLinus Torvalds lock_kernel(); 8581da177e4SLinus Torvalds mark_inode_dirty(inode); 8591da177e4SLinus Torvalds ufs_update_inode(inode, IS_SYNC(inode)); 86010e5dce0SEvgeniy Dushistov old_i_size = inode->i_size; 8611da177e4SLinus Torvalds inode->i_size = 0; 86210e5dce0SEvgeniy Dushistov if (inode->i_blocks && ufs_truncate(inode, old_i_size)) 86310e5dce0SEvgeniy Dushistov ufs_warning(inode->i_sb, __FUNCTION__, "ufs_truncate failed\n"); 8641da177e4SLinus Torvalds ufs_free_inode (inode); 8651da177e4SLinus Torvalds unlock_kernel(); 8661da177e4SLinus Torvalds } 867