| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  *  linux/fs/ufs/inode.c | 
 | 3 |  * | 
 | 4 |  * Copyright (C) 1998 | 
 | 5 |  * Daniel Pirkl <daniel.pirkl@email.cz> | 
 | 6 |  * Charles University, Faculty of Mathematics and Physics | 
 | 7 |  * | 
 | 8 |  *  from | 
 | 9 |  * | 
 | 10 |  *  linux/fs/ext2/inode.c | 
 | 11 |  * | 
 | 12 |  * Copyright (C) 1992, 1993, 1994, 1995 | 
 | 13 |  * Remy Card (card@masi.ibp.fr) | 
 | 14 |  * Laboratoire MASI - Institut Blaise Pascal | 
 | 15 |  * Universite Pierre et Marie Curie (Paris VI) | 
 | 16 |  * | 
 | 17 |  *  from | 
 | 18 |  * | 
 | 19 |  *  linux/fs/minix/inode.c | 
 | 20 |  * | 
 | 21 |  *  Copyright (C) 1991, 1992  Linus Torvalds | 
 | 22 |  * | 
 | 23 |  *  Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 | 
 | 24 |  *  Big-endian to little-endian byte-swapping/bitmaps by | 
 | 25 |  *        David S. Miller (davem@caip.rutgers.edu), 1995 | 
 | 26 |  */ | 
 | 27 |  | 
 | 28 | #include <asm/uaccess.h> | 
 | 29 | #include <asm/system.h> | 
 | 30 |  | 
 | 31 | #include <linux/errno.h> | 
 | 32 | #include <linux/fs.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | #include <linux/time.h> | 
 | 34 | #include <linux/stat.h> | 
 | 35 | #include <linux/string.h> | 
 | 36 | #include <linux/mm.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 37 | #include <linux/buffer_head.h> | 
| Christoph Hellwig | a9185b4 | 2010-03-05 09:21:37 +0100 | [diff] [blame] | 38 | #include <linux/writeback.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 |  | 
| Mike Frysinger | e542059 | 2008-02-08 04:21:31 -0800 | [diff] [blame] | 40 | #include "ufs_fs.h" | 
| Christoph Hellwig | bcd6d4e | 2007-10-16 23:26:51 -0700 | [diff] [blame] | 41 | #include "ufs.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | #include "swab.h" | 
 | 43 | #include "util.h" | 
 | 44 |  | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 45 | static u64 ufs_frag_map(struct inode *inode, sector_t frag, bool needs_lock); | 
| Adrian Bunk | 138bb68 | 2006-06-25 05:47:32 -0700 | [diff] [blame] | 46 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 47 | static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4]) | 
 | 48 | { | 
 | 49 | 	struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; | 
 | 50 | 	int ptrs = uspi->s_apb; | 
 | 51 | 	int ptrs_bits = uspi->s_apbshift; | 
 | 52 | 	const long direct_blocks = UFS_NDADDR, | 
 | 53 | 		indirect_blocks = ptrs, | 
 | 54 | 		double_blocks = (1 << (ptrs_bits * 2)); | 
 | 55 | 	int n = 0; | 
 | 56 |  | 
 | 57 |  | 
| Evgeniy Dushistov | abf5d15 | 2006-06-25 05:47:24 -0700 | [diff] [blame] | 58 | 	UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); | 
| Roel Kluin | 37044c8 | 2009-06-17 16:26:28 -0700 | [diff] [blame] | 59 | 	if (i_block < direct_blocks) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 60 | 		offsets[n++] = i_block; | 
 | 61 | 	} else if ((i_block -= direct_blocks) < indirect_blocks) { | 
 | 62 | 		offsets[n++] = UFS_IND_BLOCK; | 
 | 63 | 		offsets[n++] = i_block; | 
 | 64 | 	} else if ((i_block -= indirect_blocks) < double_blocks) { | 
 | 65 | 		offsets[n++] = UFS_DIND_BLOCK; | 
 | 66 | 		offsets[n++] = i_block >> ptrs_bits; | 
 | 67 | 		offsets[n++] = i_block & (ptrs - 1); | 
 | 68 | 	} else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { | 
 | 69 | 		offsets[n++] = UFS_TIND_BLOCK; | 
 | 70 | 		offsets[n++] = i_block >> (ptrs_bits * 2); | 
 | 71 | 		offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); | 
 | 72 | 		offsets[n++] = i_block & (ptrs - 1); | 
 | 73 | 	} else { | 
 | 74 | 		ufs_warning(inode->i_sb, "ufs_block_to_path", "block > big"); | 
 | 75 | 	} | 
 | 76 | 	return n; | 
 | 77 | } | 
 | 78 |  | 
 | 79 | /* | 
 | 80 |  * Returns the location of the fragment from | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 81 |  * the beginning of the filesystem. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 |  */ | 
 | 83 |  | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 84 | static u64 ufs_frag_map(struct inode *inode, sector_t frag, bool needs_lock) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 85 | { | 
 | 86 | 	struct ufs_inode_info *ufsi = UFS_I(inode); | 
 | 87 | 	struct super_block *sb = inode->i_sb; | 
 | 88 | 	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; | 
 | 89 | 	u64 mask = (u64) uspi->s_apbmask>>uspi->s_fpbshift; | 
 | 90 | 	int shift = uspi->s_apbshift-uspi->s_fpbshift; | 
 | 91 | 	sector_t offsets[4], *p; | 
 | 92 | 	int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets); | 
 | 93 | 	u64  ret = 0L; | 
 | 94 | 	__fs32 block; | 
 | 95 | 	__fs64 u2_block = 0L; | 
 | 96 | 	unsigned flags = UFS_SB(sb)->s_flags; | 
 | 97 | 	u64 temp = 0L; | 
 | 98 |  | 
| Evgeniy Dushistov | abf5d15 | 2006-06-25 05:47:24 -0700 | [diff] [blame] | 99 | 	UFSD(": frag = %llu  depth = %d\n", (unsigned long long)frag, depth); | 
| Andrew Morton | 7256d81 | 2006-06-29 02:24:29 -0700 | [diff] [blame] | 100 | 	UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n", | 
 | 101 | 		uspi->s_fpbshift, uspi->s_apbmask, | 
 | 102 | 		(unsigned long long)mask); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 103 |  | 
 | 104 | 	if (depth == 0) | 
 | 105 | 		return 0; | 
 | 106 |  | 
 | 107 | 	p = offsets; | 
 | 108 |  | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 109 | 	if (needs_lock) | 
 | 110 | 		lock_ufs(sb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | 	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) | 
 | 112 | 		goto ufs2; | 
 | 113 |  | 
 | 114 | 	block = ufsi->i_u1.i_data[*p++]; | 
 | 115 | 	if (!block) | 
 | 116 | 		goto out; | 
 | 117 | 	while (--depth) { | 
 | 118 | 		struct buffer_head *bh; | 
 | 119 | 		sector_t n = *p++; | 
 | 120 |  | 
 | 121 | 		bh = sb_bread(sb, uspi->s_sbbase + fs32_to_cpu(sb, block)+(n>>shift)); | 
 | 122 | 		if (!bh) | 
 | 123 | 			goto out; | 
 | 124 | 		block = ((__fs32 *) bh->b_data)[n & mask]; | 
 | 125 | 		brelse (bh); | 
 | 126 | 		if (!block) | 
 | 127 | 			goto out; | 
 | 128 | 	} | 
 | 129 | 	ret = (u64) (uspi->s_sbbase + fs32_to_cpu(sb, block) + (frag & uspi->s_fpbmask)); | 
 | 130 | 	goto out; | 
 | 131 | ufs2: | 
 | 132 | 	u2_block = ufsi->i_u1.u2_i_data[*p++]; | 
 | 133 | 	if (!u2_block) | 
 | 134 | 		goto out; | 
 | 135 |  | 
 | 136 |  | 
 | 137 | 	while (--depth) { | 
 | 138 | 		struct buffer_head *bh; | 
 | 139 | 		sector_t n = *p++; | 
 | 140 |  | 
 | 141 |  | 
 | 142 | 		temp = (u64)(uspi->s_sbbase) + fs64_to_cpu(sb, u2_block); | 
 | 143 | 		bh = sb_bread(sb, temp +(u64) (n>>shift)); | 
 | 144 | 		if (!bh) | 
 | 145 | 			goto out; | 
 | 146 | 		u2_block = ((__fs64 *)bh->b_data)[n & mask]; | 
 | 147 | 		brelse(bh); | 
 | 148 | 		if (!u2_block) | 
 | 149 | 			goto out; | 
 | 150 | 	} | 
 | 151 | 	temp = (u64)uspi->s_sbbase + fs64_to_cpu(sb, u2_block); | 
 | 152 | 	ret = temp + (u64) (frag & uspi->s_fpbmask); | 
 | 153 |  | 
 | 154 | out: | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 155 | 	if (needs_lock) | 
 | 156 | 		unlock_ufs(sb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 157 | 	return ret; | 
 | 158 | } | 
 | 159 |  | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 160 | /** | 
 | 161 |  * ufs_inode_getfrag() - allocate new fragment(s) | 
 | 162 |  * @inode - pointer to inode | 
 | 163 |  * @fragment - number of `fragment' which hold pointer | 
 | 164 |  *   to new allocated fragment(s) | 
 | 165 |  * @new_fragment - number of new allocated fragment(s) | 
 | 166 |  * @required - how many fragment(s) we require | 
 | 167 |  * @err - we set it if something wrong | 
 | 168 |  * @phys - pointer to where we save physical number of new allocated fragments, | 
 | 169 |  *   NULL if we allocate not data(indirect blocks for example). | 
 | 170 |  * @new - we set it if we allocate new block | 
 | 171 |  * @locked_page - for ufs_new_fragments() | 
 | 172 |  */ | 
 | 173 | static struct buffer_head * | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 174 | ufs_inode_getfrag(struct inode *inode, u64 fragment, | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 175 | 		  sector_t new_fragment, unsigned int required, int *err, | 
 | 176 | 		  long *phys, int *new, struct page *locked_page) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 177 | { | 
 | 178 | 	struct ufs_inode_info *ufsi = UFS_I(inode); | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 179 | 	struct super_block *sb = inode->i_sb; | 
 | 180 | 	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 181 | 	struct buffer_head * result; | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 182 | 	unsigned blockoff, lastblockoff; | 
 | 183 | 	u64 tmp, goal, lastfrag, block, lastblock; | 
 | 184 | 	void *p, *p2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 185 |  | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 186 | 	UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, required %u, " | 
 | 187 | 	     "metadata %d\n", inode->i_ino, (unsigned long long)fragment, | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 188 | 	     (unsigned long long)new_fragment, required, !phys); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 189 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 190 |         /* TODO : to be done for write support | 
 | 191 |         if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) | 
 | 192 |              goto ufs2; | 
 | 193 |          */ | 
 | 194 |  | 
 | 195 | 	block = ufs_fragstoblks (fragment); | 
 | 196 | 	blockoff = ufs_fragnum (fragment); | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 197 | 	p = ufs_get_direct_data_ptr(uspi, ufsi, block); | 
 | 198 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 199 | 	goal = 0; | 
 | 200 |  | 
 | 201 | repeat: | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 202 | 	tmp = ufs_data_ptr_to_cpu(sb, p); | 
 | 203 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 204 | 	lastfrag = ufsi->i_lastfrag; | 
 | 205 | 	if (tmp && fragment < lastfrag) { | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 206 | 		if (!phys) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 207 | 			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 208 | 			if (tmp == ufs_data_ptr_to_cpu(sb, p)) { | 
 | 209 | 				UFSD("EXIT, result %llu\n", | 
 | 210 | 				     (unsigned long long)tmp + blockoff); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 211 | 				return result; | 
 | 212 | 			} | 
 | 213 | 			brelse (result); | 
 | 214 | 			goto repeat; | 
 | 215 | 		} else { | 
| Evgeniy Dushistov | 4b25a37 | 2007-03-16 13:38:09 -0800 | [diff] [blame] | 216 | 			*phys = uspi->s_sbbase + tmp + blockoff; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 217 | 			return NULL; | 
 | 218 | 		} | 
 | 219 | 	} | 
 | 220 |  | 
 | 221 | 	lastblock = ufs_fragstoblks (lastfrag); | 
 | 222 | 	lastblockoff = ufs_fragnum (lastfrag); | 
 | 223 | 	/* | 
 | 224 | 	 * We will extend file into new block beyond last allocated block | 
 | 225 | 	 */ | 
 | 226 | 	if (lastblock < block) { | 
 | 227 | 		/* | 
 | 228 | 		 * We must reallocate last allocated block | 
 | 229 | 		 */ | 
 | 230 | 		if (lastblockoff) { | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 231 | 			p2 = ufs_get_direct_data_ptr(uspi, ufsi, lastblock); | 
 | 232 | 			tmp = ufs_new_fragments(inode, p2, lastfrag, | 
 | 233 | 						ufs_data_ptr_to_cpu(sb, p2), | 
 | 234 | 						uspi->s_fpb - lastblockoff, | 
 | 235 | 						err, locked_page); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 236 | 			if (!tmp) { | 
 | 237 | 				if (lastfrag != ufsi->i_lastfrag) | 
 | 238 | 					goto repeat; | 
 | 239 | 				else | 
 | 240 | 					return NULL; | 
 | 241 | 			} | 
 | 242 | 			lastfrag = ufsi->i_lastfrag; | 
 | 243 | 			 | 
 | 244 | 		} | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 245 | 		tmp = ufs_data_ptr_to_cpu(sb, | 
 | 246 | 					 ufs_get_direct_data_ptr(uspi, ufsi, | 
 | 247 | 								 lastblock)); | 
| Evgeniy Dushistov | c37336b | 2006-08-27 01:23:45 -0700 | [diff] [blame] | 248 | 		if (tmp) | 
 | 249 | 			goal = tmp + uspi->s_fpb; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 250 | 		tmp = ufs_new_fragments (inode, p, fragment - blockoff,  | 
| Evgeniy Dushistov | 6ef4d6b | 2006-06-25 05:47:20 -0700 | [diff] [blame] | 251 | 					 goal, required + blockoff, | 
| Evgeniy Dushistov | a685e26 | 2007-01-29 13:19:54 -0800 | [diff] [blame] | 252 | 					 err, | 
 | 253 | 					 phys != NULL ? locked_page : NULL); | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 254 | 	} else if (lastblock == block) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 255 | 	/* | 
 | 256 | 	 * We will extend last allocated block | 
 | 257 | 	 */ | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 258 | 		tmp = ufs_new_fragments(inode, p, fragment - | 
 | 259 | 					(blockoff - lastblockoff), | 
 | 260 | 					ufs_data_ptr_to_cpu(sb, p), | 
 | 261 | 					required +  (blockoff - lastblockoff), | 
| Evgeniy Dushistov | a685e26 | 2007-01-29 13:19:54 -0800 | [diff] [blame] | 262 | 					err, phys != NULL ? locked_page : NULL); | 
| Evgeniy Dushistov | c37336b | 2006-08-27 01:23:45 -0700 | [diff] [blame] | 263 | 	} else /* (lastblock > block) */ { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 264 | 	/* | 
 | 265 | 	 * We will allocate new block before last allocated block | 
 | 266 | 	 */ | 
| Evgeniy Dushistov | c37336b | 2006-08-27 01:23:45 -0700 | [diff] [blame] | 267 | 		if (block) { | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 268 | 			tmp = ufs_data_ptr_to_cpu(sb, | 
 | 269 | 						 ufs_get_direct_data_ptr(uspi, ufsi, block - 1)); | 
| Evgeniy Dushistov | c37336b | 2006-08-27 01:23:45 -0700 | [diff] [blame] | 270 | 			if (tmp) | 
 | 271 | 				goal = tmp + uspi->s_fpb; | 
 | 272 | 		} | 
| Evgeniy Dushistov | 6ef4d6b | 2006-06-25 05:47:20 -0700 | [diff] [blame] | 273 | 		tmp = ufs_new_fragments(inode, p, fragment - blockoff, | 
| Evgeniy Dushistov | a685e26 | 2007-01-29 13:19:54 -0800 | [diff] [blame] | 274 | 					goal, uspi->s_fpb, err, | 
 | 275 | 					phys != NULL ? locked_page : NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 276 | 	} | 
 | 277 | 	if (!tmp) { | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 278 | 		if ((!blockoff && ufs_data_ptr_to_cpu(sb, p)) || | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 279 | 		    (blockoff && lastfrag != ufsi->i_lastfrag)) | 
 | 280 | 			goto repeat; | 
 | 281 | 		*err = -ENOSPC; | 
 | 282 | 		return NULL; | 
 | 283 | 	} | 
 | 284 |  | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 285 | 	if (!phys) { | 
| Evgeniy Dushistov | 4b25a37 | 2007-03-16 13:38:09 -0800 | [diff] [blame] | 286 | 		result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 287 | 	} else { | 
| Evgeniy Dushistov | 4b25a37 | 2007-03-16 13:38:09 -0800 | [diff] [blame] | 288 | 		*phys = uspi->s_sbbase + tmp + blockoff; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 289 | 		result = NULL; | 
 | 290 | 		*err = 0; | 
 | 291 | 		*new = 1; | 
 | 292 | 	} | 
 | 293 |  | 
 | 294 | 	inode->i_ctime = CURRENT_TIME_SEC; | 
 | 295 | 	if (IS_SYNC(inode)) | 
 | 296 | 		ufs_sync_inode (inode); | 
 | 297 | 	mark_inode_dirty(inode); | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 298 | 	UFSD("EXIT, result %llu\n", (unsigned long long)tmp + blockoff); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 299 | 	return result; | 
 | 300 |  | 
 | 301 |      /* This part : To be implemented .... | 
 | 302 |         Required only for writing, not required for READ-ONLY. | 
 | 303 | ufs2: | 
 | 304 |  | 
 | 305 | 	u2_block = ufs_fragstoblks(fragment); | 
 | 306 | 	u2_blockoff = ufs_fragnum(fragment); | 
 | 307 | 	p = ufsi->i_u1.u2_i_data + block; | 
 | 308 | 	goal = 0; | 
 | 309 |  | 
 | 310 | repeat2: | 
 | 311 | 	tmp = fs32_to_cpu(sb, *p); | 
 | 312 | 	lastfrag = ufsi->i_lastfrag; | 
 | 313 |  | 
 | 314 |      */ | 
 | 315 | } | 
 | 316 |  | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 317 | /** | 
 | 318 |  * ufs_inode_getblock() - allocate new block | 
 | 319 |  * @inode - pointer to inode | 
 | 320 |  * @bh - pointer to block which hold "pointer" to new allocated block | 
 | 321 |  * @fragment - number of `fragment' which hold pointer | 
 | 322 |  *   to new allocated block | 
 | 323 |  * @new_fragment - number of new allocated fragment | 
 | 324 |  *  (block will hold this fragment and also uspi->s_fpb-1) | 
 | 325 |  * @err - see ufs_inode_getfrag() | 
 | 326 |  * @phys - see ufs_inode_getfrag() | 
 | 327 |  * @new - see ufs_inode_getfrag() | 
 | 328 |  * @locked_page - see ufs_inode_getfrag() | 
 | 329 |  */ | 
 | 330 | static struct buffer_head * | 
 | 331 | ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 332 | 		  u64 fragment, sector_t new_fragment, int *err, | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 333 | 		  long *phys, int *new, struct page *locked_page) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 334 | { | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 335 | 	struct super_block *sb = inode->i_sb; | 
 | 336 | 	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 337 | 	struct buffer_head * result; | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 338 | 	unsigned blockoff; | 
 | 339 | 	u64 tmp, goal, block; | 
 | 340 | 	void *p; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 341 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 342 | 	block = ufs_fragstoblks (fragment); | 
 | 343 | 	blockoff = ufs_fragnum (fragment); | 
 | 344 |  | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 345 | 	UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, metadata %d\n", | 
 | 346 | 	     inode->i_ino, (unsigned long long)fragment, | 
 | 347 | 	     (unsigned long long)new_fragment, !phys); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 348 |  | 
 | 349 | 	result = NULL; | 
 | 350 | 	if (!bh) | 
 | 351 | 		goto out; | 
 | 352 | 	if (!buffer_uptodate(bh)) { | 
 | 353 | 		ll_rw_block (READ, 1, &bh); | 
 | 354 | 		wait_on_buffer (bh); | 
 | 355 | 		if (!buffer_uptodate(bh)) | 
 | 356 | 			goto out; | 
 | 357 | 	} | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 358 | 	if (uspi->fs_magic == UFS2_MAGIC) | 
 | 359 | 		p = (__fs64 *)bh->b_data + block; | 
 | 360 | 	else | 
 | 361 | 		p = (__fs32 *)bh->b_data + block; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 362 | repeat: | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 363 | 	tmp = ufs_data_ptr_to_cpu(sb, p); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 364 | 	if (tmp) { | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 365 | 		if (!phys) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 366 | 			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 367 | 			if (tmp == ufs_data_ptr_to_cpu(sb, p)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 368 | 				goto out; | 
 | 369 | 			brelse (result); | 
 | 370 | 			goto repeat; | 
 | 371 | 		} else { | 
| Evgeniy Dushistov | 4b25a37 | 2007-03-16 13:38:09 -0800 | [diff] [blame] | 372 | 			*phys = uspi->s_sbbase + tmp + blockoff; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 373 | 			goto out; | 
 | 374 | 		} | 
 | 375 | 	} | 
 | 376 |  | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 377 | 	if (block && (uspi->fs_magic == UFS2_MAGIC ? | 
 | 378 | 		      (tmp = fs64_to_cpu(sb, ((__fs64 *)bh->b_data)[block-1])) : | 
 | 379 | 		      (tmp = fs32_to_cpu(sb, ((__fs32 *)bh->b_data)[block-1])))) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 380 | 		goal = tmp + uspi->s_fpb; | 
 | 381 | 	else | 
 | 382 | 		goal = bh->b_blocknr + uspi->s_fpb; | 
| Evgeniy Dushistov | 6ef4d6b | 2006-06-25 05:47:20 -0700 | [diff] [blame] | 383 | 	tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, | 
 | 384 | 				uspi->s_fpb, err, locked_page); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 385 | 	if (!tmp) { | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 386 | 		if (ufs_data_ptr_to_cpu(sb, p)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 387 | 			goto repeat; | 
 | 388 | 		goto out; | 
 | 389 | 	}		 | 
 | 390 |  | 
| Evgeniy Dushistov | c9a27b5 | 2006-06-25 05:47:19 -0700 | [diff] [blame] | 391 |  | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 392 | 	if (!phys) { | 
| Evgeniy Dushistov | 4b25a37 | 2007-03-16 13:38:09 -0800 | [diff] [blame] | 393 | 		result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 394 | 	} else { | 
| Evgeniy Dushistov | 4b25a37 | 2007-03-16 13:38:09 -0800 | [diff] [blame] | 395 | 		*phys = uspi->s_sbbase + tmp + blockoff; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 396 | 		*new = 1; | 
 | 397 | 	} | 
 | 398 |  | 
 | 399 | 	mark_buffer_dirty(bh); | 
 | 400 | 	if (IS_SYNC(inode)) | 
 | 401 | 		sync_dirty_buffer(bh); | 
 | 402 | 	inode->i_ctime = CURRENT_TIME_SEC; | 
 | 403 | 	mark_inode_dirty(inode); | 
| Evgeniy Dushistov | 54fb996 | 2007-02-12 00:54:32 -0800 | [diff] [blame] | 404 | 	UFSD("result %llu\n", (unsigned long long)tmp + blockoff); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 405 | out: | 
 | 406 | 	brelse (bh); | 
| Evgeniy Dushistov | abf5d15 | 2006-06-25 05:47:24 -0700 | [diff] [blame] | 407 | 	UFSD("EXIT\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 408 | 	return result; | 
 | 409 | } | 
 | 410 |  | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 411 | /** | 
| Alessio Igor Bogani | 7422caa | 2011-04-08 19:33:07 +0200 | [diff] [blame] | 412 |  * ufs_getfrag_block() - `get_block_t' function, interface between UFS and | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 413 |  * readpage, writepage and so on | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 414 |  */ | 
 | 415 |  | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 416 | int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 417 | { | 
 | 418 | 	struct super_block * sb = inode->i_sb; | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 419 | 	struct ufs_sb_info * sbi = UFS_SB(sb); | 
 | 420 | 	struct ufs_sb_private_info * uspi = sbi->s_uspi; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 421 | 	struct buffer_head * bh; | 
 | 422 | 	int ret, err, new; | 
 | 423 | 	unsigned long ptr,phys; | 
 | 424 | 	u64 phys64 = 0; | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 425 | 	bool needs_lock = (sbi->mutex_owner != current); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 426 | 	 | 
 | 427 | 	if (!create) { | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 428 | 		phys64 = ufs_frag_map(inode, fragment, needs_lock); | 
| Andrew Morton | 7256d81 | 2006-06-29 02:24:29 -0700 | [diff] [blame] | 429 | 		UFSD("phys64 = %llu\n", (unsigned long long)phys64); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 430 | 		if (phys64) | 
 | 431 | 			map_bh(bh_result, sb, phys64); | 
 | 432 | 		return 0; | 
 | 433 | 	} | 
 | 434 |  | 
 | 435 |         /* This code entered only while writing ....? */ | 
 | 436 |  | 
 | 437 | 	err = -EIO; | 
 | 438 | 	new = 0; | 
 | 439 | 	ret = 0; | 
 | 440 | 	bh = NULL; | 
 | 441 |  | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 442 | 	if (needs_lock) | 
 | 443 | 		lock_ufs(sb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 444 |  | 
| Evgeniy Dushistov | abf5d15 | 2006-06-25 05:47:24 -0700 | [diff] [blame] | 445 | 	UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 446 | 	if (fragment > | 
 | 447 | 	    ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) | 
 | 448 | 	     << uspi->s_fpbshift)) | 
 | 449 | 		goto abort_too_big; | 
 | 450 |  | 
 | 451 | 	err = 0; | 
 | 452 | 	ptr = fragment; | 
 | 453 | 	   | 
 | 454 | 	/* | 
 | 455 | 	 * ok, these macros clean the logic up a bit and make | 
 | 456 | 	 * it much more readable: | 
 | 457 | 	 */ | 
 | 458 | #define GET_INODE_DATABLOCK(x) \ | 
| Evgeniy Dushistov | a685e26 | 2007-01-29 13:19:54 -0800 | [diff] [blame] | 459 | 	ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new,\ | 
 | 460 | 			  bh_result->b_page) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 461 | #define GET_INODE_PTR(x) \ | 
| Evgeniy Dushistov | a685e26 | 2007-01-29 13:19:54 -0800 | [diff] [blame] | 462 | 	ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL,\ | 
 | 463 | 			  bh_result->b_page) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 464 | #define GET_INDIRECT_DATABLOCK(x) \ | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 465 | 	ufs_inode_getblock(inode, bh, x, fragment,	\ | 
| Evgeniy Dushistov | d63b709 | 2007-01-05 16:37:04 -0800 | [diff] [blame] | 466 | 			  &err, &phys, &new, bh_result->b_page) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 467 | #define GET_INDIRECT_PTR(x) \ | 
| Evgeniy Dushistov | 022a6dc | 2006-06-25 05:47:27 -0700 | [diff] [blame] | 468 | 	ufs_inode_getblock(inode, bh, x, fragment,	\ | 
| Evgeniy Dushistov | d63b709 | 2007-01-05 16:37:04 -0800 | [diff] [blame] | 469 | 			  &err, NULL, NULL, NULL) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 470 |  | 
 | 471 | 	if (ptr < UFS_NDIR_FRAGMENT) { | 
 | 472 | 		bh = GET_INODE_DATABLOCK(ptr); | 
 | 473 | 		goto out; | 
 | 474 | 	} | 
 | 475 | 	ptr -= UFS_NDIR_FRAGMENT; | 
 | 476 | 	if (ptr < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) { | 
 | 477 | 		bh = GET_INODE_PTR(UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift)); | 
 | 478 | 		goto get_indirect; | 
 | 479 | 	} | 
 | 480 | 	ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift); | 
 | 481 | 	if (ptr < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) { | 
 | 482 | 		bh = GET_INODE_PTR(UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift)); | 
 | 483 | 		goto get_double; | 
 | 484 | 	} | 
 | 485 | 	ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift); | 
 | 486 | 	bh = GET_INODE_PTR(UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift)); | 
 | 487 | 	bh = GET_INDIRECT_PTR((ptr >> uspi->s_2apbshift) & uspi->s_apbmask); | 
 | 488 | get_double: | 
 | 489 | 	bh = GET_INDIRECT_PTR((ptr >> uspi->s_apbshift) & uspi->s_apbmask); | 
 | 490 | get_indirect: | 
 | 491 | 	bh = GET_INDIRECT_DATABLOCK(ptr & uspi->s_apbmask); | 
 | 492 |  | 
 | 493 | #undef GET_INODE_DATABLOCK | 
 | 494 | #undef GET_INODE_PTR | 
 | 495 | #undef GET_INDIRECT_DATABLOCK | 
 | 496 | #undef GET_INDIRECT_PTR | 
 | 497 |  | 
 | 498 | out: | 
 | 499 | 	if (err) | 
 | 500 | 		goto abort; | 
 | 501 | 	if (new) | 
 | 502 | 		set_buffer_new(bh_result); | 
 | 503 | 	map_bh(bh_result, sb, phys); | 
 | 504 | abort: | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 505 | 	if (needs_lock) | 
 | 506 | 		unlock_ufs(sb); | 
 | 507 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 508 | 	return err; | 
 | 509 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 510 | abort_too_big: | 
 | 511 | 	ufs_warning(sb, "ufs_get_block", "block > big"); | 
 | 512 | 	goto abort; | 
 | 513 | } | 
 | 514 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 515 | static int ufs_writepage(struct page *page, struct writeback_control *wbc) | 
 | 516 | { | 
 | 517 | 	return block_write_full_page(page,ufs_getfrag_block,wbc); | 
 | 518 | } | 
| Nick Piggin | 82b9d1d | 2007-10-16 01:25:19 -0700 | [diff] [blame] | 519 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 520 | static int ufs_readpage(struct file *file, struct page *page) | 
 | 521 | { | 
 | 522 | 	return block_read_full_page(page,ufs_getfrag_block); | 
 | 523 | } | 
| Nick Piggin | 82b9d1d | 2007-10-16 01:25:19 -0700 | [diff] [blame] | 524 |  | 
| Christoph Hellwig | f4e420d | 2010-06-04 11:29:56 +0200 | [diff] [blame] | 525 | int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 526 | { | 
| Christoph Hellwig | 6e1db88 | 2010-06-04 11:29:57 +0200 | [diff] [blame] | 527 | 	return __block_write_begin(page, pos, len, ufs_getfrag_block); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 528 | } | 
| Nick Piggin | 82b9d1d | 2007-10-16 01:25:19 -0700 | [diff] [blame] | 529 |  | 
 | 530 | static int ufs_write_begin(struct file *file, struct address_space *mapping, | 
 | 531 | 			loff_t pos, unsigned len, unsigned flags, | 
 | 532 | 			struct page **pagep, void **fsdata) | 
 | 533 | { | 
| Christoph Hellwig | 155130a | 2010-06-04 11:29:58 +0200 | [diff] [blame] | 534 | 	int ret; | 
 | 535 |  | 
 | 536 | 	ret = block_write_begin(mapping, pos, len, flags, pagep, | 
| Christoph Hellwig | f4e420d | 2010-06-04 11:29:56 +0200 | [diff] [blame] | 537 | 				ufs_getfrag_block); | 
| Christoph Hellwig | 155130a | 2010-06-04 11:29:58 +0200 | [diff] [blame] | 538 | 	if (unlikely(ret)) { | 
 | 539 | 		loff_t isize = mapping->host->i_size; | 
 | 540 | 		if (pos + len > isize) | 
 | 541 | 			vmtruncate(mapping->host, isize); | 
 | 542 | 	} | 
 | 543 |  | 
 | 544 | 	return ret; | 
| Nick Piggin | 82b9d1d | 2007-10-16 01:25:19 -0700 | [diff] [blame] | 545 | } | 
 | 546 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 547 | static sector_t ufs_bmap(struct address_space *mapping, sector_t block) | 
 | 548 | { | 
 | 549 | 	return generic_block_bmap(mapping,block,ufs_getfrag_block); | 
 | 550 | } | 
| Nick Piggin | 82b9d1d | 2007-10-16 01:25:19 -0700 | [diff] [blame] | 551 |  | 
| Christoph Hellwig | f5e54d6 | 2006-06-28 04:26:44 -0700 | [diff] [blame] | 552 | const struct address_space_operations ufs_aops = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 553 | 	.readpage = ufs_readpage, | 
 | 554 | 	.writepage = ufs_writepage, | 
| Nick Piggin | 82b9d1d | 2007-10-16 01:25:19 -0700 | [diff] [blame] | 555 | 	.write_begin = ufs_write_begin, | 
 | 556 | 	.write_end = generic_write_end, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 557 | 	.bmap = ufs_bmap | 
 | 558 | }; | 
 | 559 |  | 
| Evgeniy Dushistov | 826843a | 2006-06-25 05:47:21 -0700 | [diff] [blame] | 560 | static void ufs_set_inode_ops(struct inode *inode) | 
 | 561 | { | 
 | 562 | 	if (S_ISREG(inode->i_mode)) { | 
 | 563 | 		inode->i_op = &ufs_file_inode_operations; | 
 | 564 | 		inode->i_fop = &ufs_file_operations; | 
 | 565 | 		inode->i_mapping->a_ops = &ufs_aops; | 
 | 566 | 	} else if (S_ISDIR(inode->i_mode)) { | 
 | 567 | 		inode->i_op = &ufs_dir_inode_operations; | 
 | 568 | 		inode->i_fop = &ufs_dir_operations; | 
 | 569 | 		inode->i_mapping->a_ops = &ufs_aops; | 
 | 570 | 	} else if (S_ISLNK(inode->i_mode)) { | 
 | 571 | 		if (!inode->i_blocks) | 
 | 572 | 			inode->i_op = &ufs_fast_symlink_inode_operations; | 
 | 573 | 		else { | 
| Dmitry Monakhov | 311b9549 | 2010-04-15 00:56:58 +0200 | [diff] [blame] | 574 | 			inode->i_op = &ufs_symlink_inode_operations; | 
| Evgeniy Dushistov | 826843a | 2006-06-25 05:47:21 -0700 | [diff] [blame] | 575 | 			inode->i_mapping->a_ops = &ufs_aops; | 
 | 576 | 		} | 
 | 577 | 	} else | 
 | 578 | 		init_special_inode(inode, inode->i_mode, | 
 | 579 | 				   ufs_get_inode_dev(inode->i_sb, UFS_I(inode))); | 
 | 580 | } | 
 | 581 |  | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 582 | static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 583 | { | 
 | 584 | 	struct ufs_inode_info *ufsi = UFS_I(inode); | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 585 | 	struct super_block *sb = inode->i_sb; | 
| Al Viro | 6a9a06d | 2011-07-26 02:49:13 -0400 | [diff] [blame] | 586 | 	umode_t mode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 587 |  | 
 | 588 | 	/* | 
 | 589 | 	 * Copy data to the in-core inode. | 
 | 590 | 	 */ | 
 | 591 | 	inode->i_mode = mode = fs16_to_cpu(sb, ufs_inode->ui_mode); | 
| Miklos Szeredi | bfe8684 | 2011-10-28 14:13:29 +0200 | [diff] [blame] | 592 | 	set_nlink(inode, fs16_to_cpu(sb, ufs_inode->ui_nlink)); | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 593 | 	if (inode->i_nlink == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 594 | 		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino); | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 595 | 		return -1; | 
 | 596 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 597 | 	 | 
 | 598 | 	/* | 
 | 599 | 	 * Linux now has 32-bit uid and gid, so we can support EFT. | 
 | 600 | 	 */ | 
 | 601 | 	inode->i_uid = ufs_get_inode_uid(sb, ufs_inode); | 
 | 602 | 	inode->i_gid = ufs_get_inode_gid(sb, ufs_inode); | 
 | 603 |  | 
 | 604 | 	inode->i_size = fs64_to_cpu(sb, ufs_inode->ui_size); | 
 | 605 | 	inode->i_atime.tv_sec = fs32_to_cpu(sb, ufs_inode->ui_atime.tv_sec); | 
 | 606 | 	inode->i_ctime.tv_sec = fs32_to_cpu(sb, ufs_inode->ui_ctime.tv_sec); | 
 | 607 | 	inode->i_mtime.tv_sec = fs32_to_cpu(sb, ufs_inode->ui_mtime.tv_sec); | 
 | 608 | 	inode->i_mtime.tv_nsec = 0; | 
 | 609 | 	inode->i_atime.tv_nsec = 0; | 
 | 610 | 	inode->i_ctime.tv_nsec = 0; | 
 | 611 | 	inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks); | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 612 | 	inode->i_generation = fs32_to_cpu(sb, ufs_inode->ui_gen); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 613 | 	ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 614 | 	ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); | 
 | 615 | 	ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 616 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 617 | 	 | 
 | 618 | 	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { | 
| Duane Griffin | f33219b | 2009-01-08 22:43:49 +0000 | [diff] [blame] | 619 | 		memcpy(ufsi->i_u1.i_data, &ufs_inode->ui_u2.ui_addr, | 
 | 620 | 		       sizeof(ufs_inode->ui_u2.ui_addr)); | 
| Evgeniy Dushistov | dd187a2 | 2006-06-25 05:47:25 -0700 | [diff] [blame] | 621 | 	} else { | 
| Duane Griffin | f33219b | 2009-01-08 22:43:49 +0000 | [diff] [blame] | 622 | 		memcpy(ufsi->i_u1.i_symlink, ufs_inode->ui_u2.ui_symlink, | 
| Duane Griffin | b12903f | 2009-01-08 22:43:50 +0000 | [diff] [blame] | 623 | 		       sizeof(ufs_inode->ui_u2.ui_symlink) - 1); | 
 | 624 | 		ufsi->i_u1.i_symlink[sizeof(ufs_inode->ui_u2.ui_symlink) - 1] = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 625 | 	} | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 626 | 	return 0; | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 627 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 628 |  | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 629 | static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 630 | { | 
 | 631 | 	struct ufs_inode_info *ufsi = UFS_I(inode); | 
 | 632 | 	struct super_block *sb = inode->i_sb; | 
| Al Viro | 6a9a06d | 2011-07-26 02:49:13 -0400 | [diff] [blame] | 633 | 	umode_t mode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 634 |  | 
| Evgeniy Dushistov | abf5d15 | 2006-06-25 05:47:24 -0700 | [diff] [blame] | 635 | 	UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 636 | 	/* | 
 | 637 | 	 * Copy data to the in-core inode. | 
 | 638 | 	 */ | 
 | 639 | 	inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode); | 
| Miklos Szeredi | bfe8684 | 2011-10-28 14:13:29 +0200 | [diff] [blame] | 640 | 	set_nlink(inode, fs16_to_cpu(sb, ufs2_inode->ui_nlink)); | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 641 | 	if (inode->i_nlink == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 642 | 		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino); | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 643 | 		return -1; | 
 | 644 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 645 |  | 
 | 646 |         /* | 
 | 647 |          * Linux now has 32-bit uid and gid, so we can support EFT. | 
 | 648 |          */ | 
 | 649 | 	inode->i_uid = fs32_to_cpu(sb, ufs2_inode->ui_uid); | 
 | 650 | 	inode->i_gid = fs32_to_cpu(sb, ufs2_inode->ui_gid); | 
 | 651 |  | 
 | 652 | 	inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size); | 
| Evgeniy Dushistov | 2189850 | 2007-03-16 13:38:07 -0800 | [diff] [blame] | 653 | 	inode->i_atime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_atime); | 
 | 654 | 	inode->i_ctime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_ctime); | 
 | 655 | 	inode->i_mtime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_mtime); | 
 | 656 | 	inode->i_atime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_atimensec); | 
 | 657 | 	inode->i_ctime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_ctimensec); | 
 | 658 | 	inode->i_mtime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_mtimensec); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 659 | 	inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks); | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 660 | 	inode->i_generation = fs32_to_cpu(sb, ufs2_inode->ui_gen); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 661 | 	ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 662 | 	/* | 
 | 663 | 	ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); | 
 | 664 | 	ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); | 
 | 665 | 	*/ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 666 |  | 
 | 667 | 	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { | 
| Duane Griffin | f33219b | 2009-01-08 22:43:49 +0000 | [diff] [blame] | 668 | 		memcpy(ufsi->i_u1.u2_i_data, &ufs2_inode->ui_u2.ui_addr, | 
 | 669 | 		       sizeof(ufs2_inode->ui_u2.ui_addr)); | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 670 | 	} else { | 
| Duane Griffin | f33219b | 2009-01-08 22:43:49 +0000 | [diff] [blame] | 671 | 		memcpy(ufsi->i_u1.i_symlink, ufs2_inode->ui_u2.ui_symlink, | 
| Duane Griffin | b12903f | 2009-01-08 22:43:50 +0000 | [diff] [blame] | 672 | 		       sizeof(ufs2_inode->ui_u2.ui_symlink) - 1); | 
 | 673 | 		ufsi->i_u1.i_symlink[sizeof(ufs2_inode->ui_u2.ui_symlink) - 1] = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 674 | 	} | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 675 | 	return 0; | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 676 | } | 
 | 677 |  | 
| David Howells | b55c460 | 2008-02-07 00:15:48 -0800 | [diff] [blame] | 678 | struct inode *ufs_iget(struct super_block *sb, unsigned long ino) | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 679 | { | 
| David Howells | b55c460 | 2008-02-07 00:15:48 -0800 | [diff] [blame] | 680 | 	struct ufs_inode_info *ufsi; | 
 | 681 | 	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 682 | 	struct buffer_head * bh; | 
| David Howells | b55c460 | 2008-02-07 00:15:48 -0800 | [diff] [blame] | 683 | 	struct inode *inode; | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 684 | 	int err; | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 685 |  | 
| David Howells | b55c460 | 2008-02-07 00:15:48 -0800 | [diff] [blame] | 686 | 	UFSD("ENTER, ino %lu\n", ino); | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 687 |  | 
| David Howells | b55c460 | 2008-02-07 00:15:48 -0800 | [diff] [blame] | 688 | 	if (ino < UFS_ROOTINO || ino > (uspi->s_ncg * uspi->s_ipg)) { | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 689 | 		ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n", | 
| David Howells | b55c460 | 2008-02-07 00:15:48 -0800 | [diff] [blame] | 690 | 			    ino); | 
 | 691 | 		return ERR_PTR(-EIO); | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 692 | 	} | 
 | 693 |  | 
| David Howells | b55c460 | 2008-02-07 00:15:48 -0800 | [diff] [blame] | 694 | 	inode = iget_locked(sb, ino); | 
 | 695 | 	if (!inode) | 
 | 696 | 		return ERR_PTR(-ENOMEM); | 
 | 697 | 	if (!(inode->i_state & I_NEW)) | 
 | 698 | 		return inode; | 
 | 699 |  | 
 | 700 | 	ufsi = UFS_I(inode); | 
 | 701 |  | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 702 | 	bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino)); | 
 | 703 | 	if (!bh) { | 
 | 704 | 		ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n", | 
 | 705 | 			    inode->i_ino); | 
 | 706 | 		goto bad_inode; | 
 | 707 | 	} | 
 | 708 | 	if ((UFS_SB(sb)->s_flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { | 
 | 709 | 		struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data; | 
 | 710 |  | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 711 | 		err = ufs2_read_inode(inode, | 
 | 712 | 				      ufs2_inode + ufs_inotofsbo(inode->i_ino)); | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 713 | 	} else { | 
 | 714 | 		struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data; | 
 | 715 |  | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 716 | 		err = ufs1_read_inode(inode, | 
 | 717 | 				      ufs_inode + ufs_inotofsbo(inode->i_ino)); | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 718 | 	} | 
 | 719 |  | 
| Evgeniy Dushistov | 07a0cfe | 2007-04-16 22:53:24 -0700 | [diff] [blame] | 720 | 	if (err) | 
 | 721 | 		goto bad_inode; | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 722 | 	inode->i_version++; | 
 | 723 | 	ufsi->i_lastfrag = | 
 | 724 | 		(inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift; | 
 | 725 | 	ufsi->i_dir_start_lookup = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 726 | 	ufsi->i_osync = 0; | 
 | 727 |  | 
| Evgeniy Dushistov | 826843a | 2006-06-25 05:47:21 -0700 | [diff] [blame] | 728 | 	ufs_set_inode_ops(inode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 729 |  | 
 | 730 | 	brelse(bh); | 
 | 731 |  | 
| Evgeniy Dushistov | abf5d15 | 2006-06-25 05:47:24 -0700 | [diff] [blame] | 732 | 	UFSD("EXIT\n"); | 
| David Howells | b55c460 | 2008-02-07 00:15:48 -0800 | [diff] [blame] | 733 | 	unlock_new_inode(inode); | 
 | 734 | 	return inode; | 
| Evgeniy Dushistov | 05f225d | 2006-06-27 02:53:59 -0700 | [diff] [blame] | 735 |  | 
 | 736 | bad_inode: | 
| David Howells | b55c460 | 2008-02-07 00:15:48 -0800 | [diff] [blame] | 737 | 	iget_failed(inode); | 
 | 738 | 	return ERR_PTR(-EIO); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 739 | } | 
 | 740 |  | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 741 | static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 742 | { | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 743 | 	struct super_block *sb = inode->i_sb; | 
 | 744 |  	struct ufs_inode_info *ufsi = UFS_I(inode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 745 |  | 
 | 746 | 	ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); | 
 | 747 | 	ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); | 
 | 748 |  | 
 | 749 | 	ufs_set_inode_uid(sb, ufs_inode, inode->i_uid); | 
 | 750 | 	ufs_set_inode_gid(sb, ufs_inode, inode->i_gid); | 
 | 751 | 		 | 
 | 752 | 	ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); | 
 | 753 | 	ufs_inode->ui_atime.tv_sec = cpu_to_fs32(sb, inode->i_atime.tv_sec); | 
 | 754 | 	ufs_inode->ui_atime.tv_usec = 0; | 
 | 755 | 	ufs_inode->ui_ctime.tv_sec = cpu_to_fs32(sb, inode->i_ctime.tv_sec); | 
 | 756 | 	ufs_inode->ui_ctime.tv_usec = 0; | 
 | 757 | 	ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, inode->i_mtime.tv_sec); | 
 | 758 | 	ufs_inode->ui_mtime.tv_usec = 0; | 
 | 759 | 	ufs_inode->ui_blocks = cpu_to_fs32(sb, inode->i_blocks); | 
 | 760 | 	ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 761 | 	ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 762 |  | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 763 | 	if ((UFS_SB(sb)->s_flags & UFS_UID_MASK) == UFS_UID_EFT) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 764 | 		ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, ufsi->i_shadow); | 
 | 765 | 		ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, ufsi->i_oeftflag); | 
 | 766 | 	} | 
 | 767 |  | 
 | 768 | 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { | 
 | 769 | 		/* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ | 
 | 770 | 		ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.i_data[0]; | 
 | 771 | 	} else if (inode->i_blocks) { | 
| Duane Griffin | f33219b | 2009-01-08 22:43:49 +0000 | [diff] [blame] | 772 | 		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.i_data, | 
 | 773 | 		       sizeof(ufs_inode->ui_u2.ui_addr)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 774 | 	} | 
 | 775 | 	else { | 
| Duane Griffin | f33219b | 2009-01-08 22:43:49 +0000 | [diff] [blame] | 776 | 		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink, | 
 | 777 | 		       sizeof(ufs_inode->ui_u2.ui_symlink)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 778 | 	} | 
 | 779 |  | 
 | 780 | 	if (!inode->i_nlink) | 
 | 781 | 		memset (ufs_inode, 0, sizeof(struct ufs_inode)); | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 782 | } | 
 | 783 |  | 
 | 784 | static void ufs2_update_inode(struct inode *inode, struct ufs2_inode *ufs_inode) | 
 | 785 | { | 
 | 786 | 	struct super_block *sb = inode->i_sb; | 
 | 787 |  	struct ufs_inode_info *ufsi = UFS_I(inode); | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 788 |  | 
 | 789 | 	UFSD("ENTER\n"); | 
 | 790 | 	ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); | 
 | 791 | 	ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); | 
 | 792 |  | 
 | 793 | 	ufs_inode->ui_uid = cpu_to_fs32(sb, inode->i_uid); | 
 | 794 | 	ufs_inode->ui_gid = cpu_to_fs32(sb, inode->i_gid); | 
 | 795 |  | 
 | 796 | 	ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); | 
| Evgeniy Dushistov | 2189850 | 2007-03-16 13:38:07 -0800 | [diff] [blame] | 797 | 	ufs_inode->ui_atime = cpu_to_fs64(sb, inode->i_atime.tv_sec); | 
 | 798 | 	ufs_inode->ui_atimensec = cpu_to_fs32(sb, inode->i_atime.tv_nsec); | 
 | 799 | 	ufs_inode->ui_ctime = cpu_to_fs64(sb, inode->i_ctime.tv_sec); | 
 | 800 | 	ufs_inode->ui_ctimensec = cpu_to_fs32(sb, inode->i_ctime.tv_nsec); | 
 | 801 | 	ufs_inode->ui_mtime = cpu_to_fs64(sb, inode->i_mtime.tv_sec); | 
 | 802 | 	ufs_inode->ui_mtimensec = cpu_to_fs32(sb, inode->i_mtime.tv_nsec); | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 803 |  | 
 | 804 | 	ufs_inode->ui_blocks = cpu_to_fs64(sb, inode->i_blocks); | 
 | 805 | 	ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); | 
 | 806 | 	ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation); | 
 | 807 |  | 
 | 808 | 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { | 
 | 809 | 		/* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ | 
 | 810 | 		ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.u2_i_data[0]; | 
 | 811 | 	} else if (inode->i_blocks) { | 
| Duane Griffin | f33219b | 2009-01-08 22:43:49 +0000 | [diff] [blame] | 812 | 		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.u2_i_data, | 
 | 813 | 		       sizeof(ufs_inode->ui_u2.ui_addr)); | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 814 | 	} else { | 
| Duane Griffin | f33219b | 2009-01-08 22:43:49 +0000 | [diff] [blame] | 815 | 		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink, | 
 | 816 | 		       sizeof(ufs_inode->ui_u2.ui_symlink)); | 
| Evgeniy Dushistov | 3313e29 | 2007-02-12 00:54:31 -0800 | [diff] [blame] | 817 |  	} | 
 | 818 |  | 
 | 819 | 	if (!inode->i_nlink) | 
 | 820 | 		memset (ufs_inode, 0, sizeof(struct ufs2_inode)); | 
 | 821 | 	UFSD("EXIT\n"); | 
 | 822 | } | 
 | 823 |  | 
 | 824 | static int ufs_update_inode(struct inode * inode, int do_sync) | 
 | 825 | { | 
 | 826 | 	struct super_block *sb = inode->i_sb; | 
 | 827 | 	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; | 
 | 828 | 	struct buffer_head * bh; | 
 | 829 |  | 
 | 830 | 	UFSD("ENTER, ino %lu\n", inode->i_ino); | 
 | 831 |  | 
 | 832 | 	if (inode->i_ino < UFS_ROOTINO || | 
 | 833 | 	    inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { | 
 | 834 | 		ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); | 
 | 835 | 		return -1; | 
 | 836 | 	} | 
 | 837 |  | 
 | 838 | 	bh = sb_bread(sb, ufs_inotofsba(inode->i_ino)); | 
 | 839 | 	if (!bh) { | 
 | 840 | 		ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); | 
 | 841 | 		return -1; | 
 | 842 | 	} | 
 | 843 | 	if (uspi->fs_magic == UFS2_MAGIC) { | 
 | 844 | 		struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data; | 
 | 845 |  | 
 | 846 | 		ufs2_update_inode(inode, | 
 | 847 | 				  ufs2_inode + ufs_inotofsbo(inode->i_ino)); | 
 | 848 | 	} else { | 
 | 849 | 		struct ufs_inode *ufs_inode = (struct ufs_inode *) bh->b_data; | 
 | 850 |  | 
 | 851 | 		ufs1_update_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino)); | 
 | 852 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 853 | 		 | 
 | 854 | 	mark_buffer_dirty(bh); | 
 | 855 | 	if (do_sync) | 
 | 856 | 		sync_dirty_buffer(bh); | 
 | 857 | 	brelse (bh); | 
 | 858 | 	 | 
| Evgeniy Dushistov | abf5d15 | 2006-06-25 05:47:24 -0700 | [diff] [blame] | 859 | 	UFSD("EXIT\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 860 | 	return 0; | 
 | 861 | } | 
 | 862 |  | 
| Christoph Hellwig | a9185b4 | 2010-03-05 09:21:37 +0100 | [diff] [blame] | 863 | int ufs_write_inode(struct inode *inode, struct writeback_control *wbc) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 864 | { | 
 | 865 | 	int ret; | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 866 | 	lock_ufs(inode->i_sb); | 
| Christoph Hellwig | a9185b4 | 2010-03-05 09:21:37 +0100 | [diff] [blame] | 867 | 	ret = ufs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL); | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 868 | 	unlock_ufs(inode->i_sb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 869 | 	return ret; | 
 | 870 | } | 
 | 871 |  | 
 | 872 | int ufs_sync_inode (struct inode *inode) | 
 | 873 | { | 
 | 874 | 	return ufs_update_inode (inode, 1); | 
 | 875 | } | 
 | 876 |  | 
| Al Viro | 58e8268 | 2010-06-05 19:40:56 -0400 | [diff] [blame] | 877 | void ufs_evict_inode(struct inode * inode) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 878 | { | 
| Al Viro | 58e8268 | 2010-06-05 19:40:56 -0400 | [diff] [blame] | 879 | 	int want_delete = 0; | 
 | 880 |  | 
 | 881 | 	if (!inode->i_nlink && !is_bad_inode(inode)) | 
 | 882 | 		want_delete = 1; | 
| Evgeniy Dushistov | 10e5dce | 2006-07-01 04:36:24 -0700 | [diff] [blame] | 883 |  | 
| Mark Fasheh | fef2665 | 2005-09-09 13:01:31 -0700 | [diff] [blame] | 884 | 	truncate_inode_pages(&inode->i_data, 0); | 
| Al Viro | 58e8268 | 2010-06-05 19:40:56 -0400 | [diff] [blame] | 885 | 	if (want_delete) { | 
 | 886 | 		loff_t old_i_size; | 
 | 887 | 		/*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 888 | 		lock_ufs(inode->i_sb); | 
| Al Viro | 58e8268 | 2010-06-05 19:40:56 -0400 | [diff] [blame] | 889 | 		mark_inode_dirty(inode); | 
 | 890 | 		ufs_update_inode(inode, IS_SYNC(inode)); | 
 | 891 | 		old_i_size = inode->i_size; | 
 | 892 | 		inode->i_size = 0; | 
 | 893 | 		if (inode->i_blocks && ufs_truncate(inode, old_i_size)) | 
 | 894 | 			ufs_warning(inode->i_sb, __func__, "ufs_truncate failed\n"); | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 895 | 		unlock_ufs(inode->i_sb); | 
| Al Viro | 58e8268 | 2010-06-05 19:40:56 -0400 | [diff] [blame] | 896 | 	} | 
 | 897 |  | 
 | 898 | 	invalidate_inode_buffers(inode); | 
 | 899 | 	end_writeback(inode); | 
 | 900 |  | 
 | 901 | 	if (want_delete) { | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 902 | 		lock_ufs(inode->i_sb); | 
| Al Viro | 58e8268 | 2010-06-05 19:40:56 -0400 | [diff] [blame] | 903 | 		ufs_free_inode (inode); | 
| Arnd Bergmann | 788257d | 2011-01-24 10:14:12 +0100 | [diff] [blame] | 904 | 		unlock_ufs(inode->i_sb); | 
| Al Viro | 58e8268 | 2010-06-05 19:40:56 -0400 | [diff] [blame] | 905 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 906 | } |