Blame view
fs/xfs/xfs_dir2.c
16 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
7b7187698 [XFS] Update lice... |
2 3 |
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. |
1da177e4c Linux-2.6.12-rc2 |
4 |
* |
7b7187698 [XFS] Update lice... |
5 6 |
* This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as |
1da177e4c Linux-2.6.12-rc2 |
7 8 |
* published by the Free Software Foundation. * |
7b7187698 [XFS] Update lice... |
9 10 11 12 |
* This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. |
1da177e4c Linux-2.6.12-rc2 |
13 |
* |
7b7187698 [XFS] Update lice... |
14 15 16 |
* You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
1da177e4c Linux-2.6.12-rc2 |
17 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
18 |
#include "xfs.h" |
a844f4510 [XFS] Remove xfs_... |
19 |
#include "xfs_fs.h" |
1da177e4c Linux-2.6.12-rc2 |
20 |
#include "xfs_types.h" |
a844f4510 [XFS] Remove xfs_... |
21 |
#include "xfs_bit.h" |
1da177e4c Linux-2.6.12-rc2 |
22 |
#include "xfs_log.h" |
a844f4510 [XFS] Remove xfs_... |
23 |
#include "xfs_inum.h" |
1da177e4c Linux-2.6.12-rc2 |
24 25 26 |
#include "xfs_trans.h" #include "xfs_sb.h" #include "xfs_ag.h" |
1da177e4c Linux-2.6.12-rc2 |
27 |
#include "xfs_mount.h" |
a844f4510 [XFS] Remove xfs_... |
28 |
#include "xfs_da_btree.h" |
1da177e4c Linux-2.6.12-rc2 |
29 |
#include "xfs_bmap_btree.h" |
a844f4510 [XFS] Remove xfs_... |
30 |
#include "xfs_alloc_btree.h" |
1da177e4c Linux-2.6.12-rc2 |
31 |
#include "xfs_dinode.h" |
1da177e4c Linux-2.6.12-rc2 |
32 |
#include "xfs_inode.h" |
a844f4510 [XFS] Remove xfs_... |
33 |
#include "xfs_inode_item.h" |
1da177e4c Linux-2.6.12-rc2 |
34 |
#include "xfs_bmap.h" |
579266407 xfs: reshuffle di... |
35 36 37 |
#include "xfs_dir2.h" #include "xfs_dir2_format.h" #include "xfs_dir2_priv.h" |
1da177e4c Linux-2.6.12-rc2 |
38 |
#include "xfs_error.h" |
a8272ce0c [XFS] Fix up spar... |
39 |
#include "xfs_vnodeops.h" |
0b1b213fc xfs: event tracin... |
40 |
#include "xfs_trace.h" |
1da177e4c Linux-2.6.12-rc2 |
41 |
|
4a24cb714 xfs: clean up sig... |
42 |
struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2}; |
1da177e4c Linux-2.6.12-rc2 |
43 |
|
189f4bf22 [XFS] XFS: ASCII ... |
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/* * ASCII case-insensitive (ie. A-Z) support for directories that was * used in IRIX. */ STATIC xfs_dahash_t xfs_ascii_ci_hashname( struct xfs_name *name) { xfs_dahash_t hash; int i; for (i = 0, hash = 0; i < name->len; i++) hash = tolower(name->name[i]) ^ rol32(hash, 7); return hash; } STATIC enum xfs_dacmp xfs_ascii_ci_compname( struct xfs_da_args *args, |
2bc754213 xfs: convert dirn... |
64 65 |
const unsigned char *name, int len) |
189f4bf22 [XFS] XFS: ASCII ... |
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
{ enum xfs_dacmp result; int i; if (args->namelen != len) return XFS_CMP_DIFFERENT; result = XFS_CMP_EXACT; for (i = 0; i < len; i++) { if (args->name[i] == name[i]) continue; if (tolower(args->name[i]) != tolower(name[i])) return XFS_CMP_DIFFERENT; result = XFS_CMP_CASE; } return result; } static struct xfs_nameops xfs_ascii_ci_nameops = { .hashname = xfs_ascii_ci_hashname, .compname = xfs_ascii_ci_compname, }; |
f6c2d1fa6 [XFS] Remove vers... |
89 90 91 |
void xfs_dir_mount( xfs_mount_t *mp) |
1da177e4c Linux-2.6.12-rc2 |
92 |
{ |
621187099 [XFS] remove shou... |
93 |
ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb)); |
1da177e4c Linux-2.6.12-rc2 |
94 95 96 97 |
ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <= XFS_MAX_BLOCKSIZE); mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog); mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog; |
bbaaf5380 [XFS] Reduce shou... |
98 99 100 |
mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp)); mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp)); mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp)); |
1da177e4c Linux-2.6.12-rc2 |
101 102 103 104 105 106 107 |
mp->m_attr_node_ents = (mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) / (uint)sizeof(xfs_da_node_entry_t); mp->m_dir_node_ents = (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / (uint)sizeof(xfs_da_node_entry_t); mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; |
189f4bf22 [XFS] XFS: ASCII ... |
108 109 110 111 |
if (xfs_sb_version_hasasciici(&mp->m_sb)) mp->m_dirnameops = &xfs_ascii_ci_nameops; else mp->m_dirnameops = &xfs_default_nameops; |
1da177e4c Linux-2.6.12-rc2 |
112 113 114 115 116 |
} /* * Return 1 if directory contains only "." and "..". */ |
f6c2d1fa6 [XFS] Remove vers... |
117 118 119 |
int xfs_dir_isempty( xfs_inode_t *dp) |
1da177e4c Linux-2.6.12-rc2 |
120 |
{ |
ac8ba50f6 xfs: kill struct ... |
121 |
xfs_dir2_sf_hdr_t *sfp; |
1da177e4c Linux-2.6.12-rc2 |
122 |
|
abbede1b3 xfs: get rid of o... |
123 |
ASSERT(S_ISDIR(dp->i_d.di_mode)); |
f6c2d1fa6 [XFS] Remove vers... |
124 |
if (dp->i_d.di_size == 0) /* might happen during shutdown. */ |
1da177e4c Linux-2.6.12-rc2 |
125 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
126 127 |
if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) return 0; |
ac8ba50f6 xfs: kill struct ... |
128 129 |
sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; return !sfp->count; |
1da177e4c Linux-2.6.12-rc2 |
130 131 132 |
} /* |
f6c2d1fa6 [XFS] Remove vers... |
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
* Validate a given inode number. */ int xfs_dir_ino_validate( xfs_mount_t *mp, xfs_ino_t ino) { xfs_agblock_t agblkno; xfs_agino_t agino; xfs_agnumber_t agno; int ino_ok; int ioff; agno = XFS_INO_TO_AGNO(mp, ino); agblkno = XFS_INO_TO_AGBNO(mp, ino); ioff = XFS_INO_TO_OFFSET(mp, ino); agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff); ino_ok = agno < mp->m_sb.sb_agcount && agblkno < mp->m_sb.sb_agblocks && agblkno != 0 && ioff < (1 << mp->m_sb.sb_inopblog) && XFS_AGINO_TO_INO(mp, agno, agino) == ino; if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE, XFS_RANDOM_DIR_INO_VALIDATE))) { |
534877869 xfs: convert xfs_... |
158 |
xfs_warn(mp, "Invalid inode number 0x%Lx", |
f6c2d1fa6 [XFS] Remove vers... |
159 160 161 162 163 164 165 166 |
(unsigned long long) ino); XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp); return XFS_ERROR(EFSCORRUPTED); } return 0; } /* |
1da177e4c Linux-2.6.12-rc2 |
167 168 |
* Initialize a directory with its "." and ".." entries. */ |
f6c2d1fa6 [XFS] Remove vers... |
169 170 171 172 173 |
int xfs_dir_init( xfs_trans_t *tp, xfs_inode_t *dp, xfs_inode_t *pdp) |
1da177e4c Linux-2.6.12-rc2 |
174 |
{ |
f6c2d1fa6 [XFS] Remove vers... |
175 176 |
xfs_da_args_t args; int error; |
1da177e4c Linux-2.6.12-rc2 |
177 178 179 180 |
memset((char *)&args, 0, sizeof(args)); args.dp = dp; args.trans = tp; |
abbede1b3 xfs: get rid of o... |
181 |
ASSERT(S_ISDIR(dp->i_d.di_mode)); |
f6c2d1fa6 [XFS] Remove vers... |
182 |
if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) |
1da177e4c Linux-2.6.12-rc2 |
183 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
184 185 186 187 188 189 |
return xfs_dir2_sf_create(&args, pdp->i_ino); } /* Enter a name in a directory. */ |
f6c2d1fa6 [XFS] Remove vers... |
190 191 192 193 |
int xfs_dir_createname( xfs_trans_t *tp, xfs_inode_t *dp, |
556b8b166 [XFS] remove bhv_... |
194 |
struct xfs_name *name, |
1da177e4c Linux-2.6.12-rc2 |
195 196 197 198 199 |
xfs_ino_t inum, /* new entry inode number */ xfs_fsblock_t *first, /* bmap's firstblock */ xfs_bmap_free_t *flist, /* bmap's freeblock list */ xfs_extlen_t total) /* bmap's total block count */ { |
f6c2d1fa6 [XFS] Remove vers... |
200 201 |
xfs_da_args_t args; int rval; |
1da177e4c Linux-2.6.12-rc2 |
202 |
int v; /* type-checking value */ |
abbede1b3 xfs: get rid of o... |
203 |
ASSERT(S_ISDIR(dp->i_d.di_mode)); |
f6c2d1fa6 [XFS] Remove vers... |
204 |
if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) |
1da177e4c Linux-2.6.12-rc2 |
205 |
return rval; |
1da177e4c Linux-2.6.12-rc2 |
206 |
XFS_STATS_INC(xs_dir_create); |
f6c2d1fa6 [XFS] Remove vers... |
207 |
|
87affd08b [XFS] Zero uninit... |
208 |
memset(&args, 0, sizeof(xfs_da_args_t)); |
556b8b166 [XFS] remove bhv_... |
209 210 |
args.name = name->name; args.namelen = name->len; |
5163f95a0 [XFS] Name operat... |
211 |
args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
1da177e4c Linux-2.6.12-rc2 |
212 213 214 215 216 217 218 |
args.inumber = inum; args.dp = dp; args.firstblock = first; args.flist = flist; args.total = total; args.whichfork = XFS_DATA_FORK; args.trans = tp; |
6a178100a [XFS] Add op_flag... |
219 |
args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; |
f6c2d1fa6 [XFS] Remove vers... |
220 |
|
1da177e4c Linux-2.6.12-rc2 |
221 222 |
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) rval = xfs_dir2_sf_addname(&args); |
f6c2d1fa6 [XFS] Remove vers... |
223 |
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
224 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
225 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
226 |
rval = xfs_dir2_block_addname(&args); |
f6c2d1fa6 [XFS] Remove vers... |
227 |
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
228 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
229 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
230 231 232 233 234 235 236 |
rval = xfs_dir2_leaf_addname(&args); else rval = xfs_dir2_node_addname(&args); return rval; } /* |
384f3ced0 [XFS] Return case... |
237 238 239 240 241 242 |
* If doing a CI lookup and case-insensitive match, dup actual name into * args.value. Return EEXIST for success (ie. name found) or an error. */ int xfs_dir_cilookup_result( struct xfs_da_args *args, |
a3380ae39 xfs: make xfs_dir... |
243 |
const unsigned char *name, |
384f3ced0 [XFS] Return case... |
244 245 246 247 248 249 250 |
int len) { if (args->cmpresult == XFS_CMP_DIFFERENT) return ENOENT; if (args->cmpresult != XFS_CMP_CASE || !(args->op_flags & XFS_DA_OP_CILOOKUP)) return EEXIST; |
3f52c2f0a xfs: switch to NO... |
251 |
args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL); |
384f3ced0 [XFS] Return case... |
252 253 254 255 256 257 258 259 260 |
if (!args->value) return ENOMEM; memcpy(args->value, name, len); args->valuelen = len; return EEXIST; } /* |
1da177e4c Linux-2.6.12-rc2 |
261 |
* Lookup a name in a directory, give back the inode number. |
384f3ced0 [XFS] Return case... |
262 263 |
* If ci_name is not NULL, returns the actual name in ci_name if it differs * to name, or ci_name->name is set to NULL for an exact match. |
1da177e4c Linux-2.6.12-rc2 |
264 |
*/ |
384f3ced0 [XFS] Return case... |
265 |
|
f6c2d1fa6 [XFS] Remove vers... |
266 267 268 269 |
int xfs_dir_lookup( xfs_trans_t *tp, xfs_inode_t *dp, |
556b8b166 [XFS] remove bhv_... |
270 |
struct xfs_name *name, |
384f3ced0 [XFS] Return case... |
271 272 |
xfs_ino_t *inum, /* out: inode number */ struct xfs_name *ci_name) /* out: actual name if CI match */ |
1da177e4c Linux-2.6.12-rc2 |
273 |
{ |
f6c2d1fa6 [XFS] Remove vers... |
274 275 |
xfs_da_args_t args; int rval; |
1da177e4c Linux-2.6.12-rc2 |
276 |
int v; /* type-checking value */ |
abbede1b3 xfs: get rid of o... |
277 |
ASSERT(S_ISDIR(dp->i_d.di_mode)); |
1da177e4c Linux-2.6.12-rc2 |
278 |
XFS_STATS_INC(xs_dir_lookup); |
87affd08b [XFS] Zero uninit... |
279 |
memset(&args, 0, sizeof(xfs_da_args_t)); |
556b8b166 [XFS] remove bhv_... |
280 281 |
args.name = name->name; args.namelen = name->len; |
5163f95a0 [XFS] Name operat... |
282 |
args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
1da177e4c Linux-2.6.12-rc2 |
283 |
args.dp = dp; |
1da177e4c Linux-2.6.12-rc2 |
284 285 |
args.whichfork = XFS_DATA_FORK; args.trans = tp; |
6a178100a [XFS] Add op_flag... |
286 |
args.op_flags = XFS_DA_OP_OKNOENT; |
384f3ced0 [XFS] Return case... |
287 288 |
if (ci_name) args.op_flags |= XFS_DA_OP_CILOOKUP; |
f6c2d1fa6 [XFS] Remove vers... |
289 |
|
1da177e4c Linux-2.6.12-rc2 |
290 291 |
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) rval = xfs_dir2_sf_lookup(&args); |
f6c2d1fa6 [XFS] Remove vers... |
292 |
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
293 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
294 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
295 |
rval = xfs_dir2_block_lookup(&args); |
f6c2d1fa6 [XFS] Remove vers... |
296 |
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
297 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
298 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
299 300 301 302 303 |
rval = xfs_dir2_leaf_lookup(&args); else rval = xfs_dir2_node_lookup(&args); if (rval == EEXIST) rval = 0; |
384f3ced0 [XFS] Return case... |
304 |
if (!rval) { |
1da177e4c Linux-2.6.12-rc2 |
305 |
*inum = args.inumber; |
384f3ced0 [XFS] Return case... |
306 307 308 309 310 |
if (ci_name) { ci_name->name = args.value; ci_name->len = args.valuelen; } } |
1da177e4c Linux-2.6.12-rc2 |
311 312 313 314 315 316 |
return rval; } /* * Remove an entry from a directory. */ |
f6c2d1fa6 [XFS] Remove vers... |
317 318 319 320 |
int xfs_dir_removename( xfs_trans_t *tp, xfs_inode_t *dp, |
556b8b166 [XFS] remove bhv_... |
321 |
struct xfs_name *name, |
f6c2d1fa6 [XFS] Remove vers... |
322 |
xfs_ino_t ino, |
1da177e4c Linux-2.6.12-rc2 |
323 324 325 326 |
xfs_fsblock_t *first, /* bmap's firstblock */ xfs_bmap_free_t *flist, /* bmap's freeblock list */ xfs_extlen_t total) /* bmap's total block count */ { |
f6c2d1fa6 [XFS] Remove vers... |
327 328 |
xfs_da_args_t args; int rval; |
1da177e4c Linux-2.6.12-rc2 |
329 |
int v; /* type-checking value */ |
abbede1b3 xfs: get rid of o... |
330 |
ASSERT(S_ISDIR(dp->i_d.di_mode)); |
1da177e4c Linux-2.6.12-rc2 |
331 |
XFS_STATS_INC(xs_dir_remove); |
f6c2d1fa6 [XFS] Remove vers... |
332 |
|
87affd08b [XFS] Zero uninit... |
333 |
memset(&args, 0, sizeof(xfs_da_args_t)); |
556b8b166 [XFS] remove bhv_... |
334 335 |
args.name = name->name; args.namelen = name->len; |
5163f95a0 [XFS] Name operat... |
336 |
args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
1da177e4c Linux-2.6.12-rc2 |
337 338 339 340 341 342 343 |
args.inumber = ino; args.dp = dp; args.firstblock = first; args.flist = flist; args.total = total; args.whichfork = XFS_DATA_FORK; args.trans = tp; |
f6c2d1fa6 [XFS] Remove vers... |
344 |
|
1da177e4c Linux-2.6.12-rc2 |
345 346 |
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) rval = xfs_dir2_sf_removename(&args); |
f6c2d1fa6 [XFS] Remove vers... |
347 |
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
348 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
349 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
350 |
rval = xfs_dir2_block_removename(&args); |
f6c2d1fa6 [XFS] Remove vers... |
351 |
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
352 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
353 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
354 355 356 357 358 359 360 361 362 |
rval = xfs_dir2_leaf_removename(&args); else rval = xfs_dir2_node_removename(&args); return rval; } /* * Read a directory. */ |
f6c2d1fa6 [XFS] Remove vers... |
363 |
int |
051e7cd44 [XFS] use filldir... |
364 |
xfs_readdir( |
993386c19 [XFS] decontamina... |
365 |
xfs_inode_t *dp, |
051e7cd44 [XFS] use filldir... |
366 367 368 369 |
void *dirent, size_t bufsize, xfs_off_t *offset, filldir_t filldir) |
1da177e4c Linux-2.6.12-rc2 |
370 |
{ |
1da177e4c Linux-2.6.12-rc2 |
371 372 |
int rval; /* return value */ int v; /* type-checking value */ |
cca28fb83 xfs: split xfs_it... |
373 |
trace_xfs_readdir(dp); |
051e7cd44 [XFS] use filldir... |
374 375 376 |
if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return XFS_ERROR(EIO); |
abbede1b3 xfs: get rid of o... |
377 |
ASSERT(S_ISDIR(dp->i_d.di_mode)); |
1da177e4c Linux-2.6.12-rc2 |
378 |
XFS_STATS_INC(xs_dir_getdents); |
1da177e4c Linux-2.6.12-rc2 |
379 |
|
1da177e4c Linux-2.6.12-rc2 |
380 |
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
051e7cd44 [XFS] use filldir... |
381 382 |
rval = xfs_dir2_sf_getdents(dp, dirent, offset, filldir); else if ((rval = xfs_dir2_isblock(NULL, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
383 |
; |
f6c2d1fa6 [XFS] Remove vers... |
384 |
else if (v) |
051e7cd44 [XFS] use filldir... |
385 |
rval = xfs_dir2_block_getdents(dp, dirent, offset, filldir); |
1da177e4c Linux-2.6.12-rc2 |
386 |
else |
051e7cd44 [XFS] use filldir... |
387 388 |
rval = xfs_dir2_leaf_getdents(dp, dirent, bufsize, offset, filldir); |
1da177e4c Linux-2.6.12-rc2 |
389 390 391 392 393 394 |
return rval; } /* * Replace the inode number of a directory entry. */ |
f6c2d1fa6 [XFS] Remove vers... |
395 396 397 398 |
int xfs_dir_replace( xfs_trans_t *tp, xfs_inode_t *dp, |
556b8b166 [XFS] remove bhv_... |
399 |
struct xfs_name *name, /* name of entry to replace */ |
1da177e4c Linux-2.6.12-rc2 |
400 401 402 403 404 |
xfs_ino_t inum, /* new inode number */ xfs_fsblock_t *first, /* bmap's firstblock */ xfs_bmap_free_t *flist, /* bmap's freeblock list */ xfs_extlen_t total) /* bmap's total block count */ { |
f6c2d1fa6 [XFS] Remove vers... |
405 406 |
xfs_da_args_t args; int rval; |
1da177e4c Linux-2.6.12-rc2 |
407 |
int v; /* type-checking value */ |
abbede1b3 xfs: get rid of o... |
408 |
ASSERT(S_ISDIR(dp->i_d.di_mode)); |
1da177e4c Linux-2.6.12-rc2 |
409 |
|
f6c2d1fa6 [XFS] Remove vers... |
410 |
if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) |
1da177e4c Linux-2.6.12-rc2 |
411 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
412 |
|
87affd08b [XFS] Zero uninit... |
413 |
memset(&args, 0, sizeof(xfs_da_args_t)); |
556b8b166 [XFS] remove bhv_... |
414 415 |
args.name = name->name; args.namelen = name->len; |
5163f95a0 [XFS] Name operat... |
416 |
args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
1da177e4c Linux-2.6.12-rc2 |
417 418 419 420 421 422 423 |
args.inumber = inum; args.dp = dp; args.firstblock = first; args.flist = flist; args.total = total; args.whichfork = XFS_DATA_FORK; args.trans = tp; |
f6c2d1fa6 [XFS] Remove vers... |
424 |
|
1da177e4c Linux-2.6.12-rc2 |
425 426 |
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) rval = xfs_dir2_sf_replace(&args); |
f6c2d1fa6 [XFS] Remove vers... |
427 |
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
428 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
429 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
430 |
rval = xfs_dir2_block_replace(&args); |
f6c2d1fa6 [XFS] Remove vers... |
431 |
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
432 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
433 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
434 435 436 437 438 439 440 441 |
rval = xfs_dir2_leaf_replace(&args); else rval = xfs_dir2_node_replace(&args); return rval; } /* * See if this entry can be added to the directory without allocating space. |
556b8b166 [XFS] remove bhv_... |
442 |
* First checks that the caller couldn't reserve enough space (resblks = 0). |
1da177e4c Linux-2.6.12-rc2 |
443 |
*/ |
f6c2d1fa6 [XFS] Remove vers... |
444 445 446 447 |
int xfs_dir_canenter( xfs_trans_t *tp, xfs_inode_t *dp, |
556b8b166 [XFS] remove bhv_... |
448 449 |
struct xfs_name *name, /* name of entry to add */ uint resblks) |
1da177e4c Linux-2.6.12-rc2 |
450 |
{ |
f6c2d1fa6 [XFS] Remove vers... |
451 452 |
xfs_da_args_t args; int rval; |
1da177e4c Linux-2.6.12-rc2 |
453 |
int v; /* type-checking value */ |
556b8b166 [XFS] remove bhv_... |
454 455 |
if (resblks) return 0; |
abbede1b3 xfs: get rid of o... |
456 |
ASSERT(S_ISDIR(dp->i_d.di_mode)); |
f6c2d1fa6 [XFS] Remove vers... |
457 |
|
87affd08b [XFS] Zero uninit... |
458 |
memset(&args, 0, sizeof(xfs_da_args_t)); |
556b8b166 [XFS] remove bhv_... |
459 460 |
args.name = name->name; args.namelen = name->len; |
5163f95a0 [XFS] Name operat... |
461 |
args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
1da177e4c Linux-2.6.12-rc2 |
462 |
args.dp = dp; |
1da177e4c Linux-2.6.12-rc2 |
463 464 |
args.whichfork = XFS_DATA_FORK; args.trans = tp; |
6a178100a [XFS] Add op_flag... |
465 466 |
args.op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; |
f6c2d1fa6 [XFS] Remove vers... |
467 |
|
1da177e4c Linux-2.6.12-rc2 |
468 469 |
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) rval = xfs_dir2_sf_addname(&args); |
f6c2d1fa6 [XFS] Remove vers... |
470 |
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
471 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
472 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
473 |
rval = xfs_dir2_block_addname(&args); |
f6c2d1fa6 [XFS] Remove vers... |
474 |
else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
1da177e4c Linux-2.6.12-rc2 |
475 |
return rval; |
f6c2d1fa6 [XFS] Remove vers... |
476 |
else if (v) |
1da177e4c Linux-2.6.12-rc2 |
477 478 479 480 481 482 483 |
rval = xfs_dir2_leaf_addname(&args); else rval = xfs_dir2_node_addname(&args); return rval; } /* |
1da177e4c Linux-2.6.12-rc2 |
484 485 486 487 488 |
* Utility routines. */ /* * Add a block to the directory. |
77936d028 xfs: factor out x... |
489 490 491 |
* * This routine is for data and free blocks, not leaf/node blocks which are * handled by xfs_da_grow_inode. |
1da177e4c Linux-2.6.12-rc2 |
492 |
*/ |
f6c2d1fa6 [XFS] Remove vers... |
493 |
int |
1da177e4c Linux-2.6.12-rc2 |
494 |
xfs_dir2_grow_inode( |
77936d028 xfs: factor out x... |
495 496 497 |
struct xfs_da_args *args, int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ xfs_dir2_db_t *dbp) /* out: block number added */ |
1da177e4c Linux-2.6.12-rc2 |
498 |
{ |
77936d028 xfs: factor out x... |
499 500 501 502 503 |
struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; xfs_fileoff_t bno; /* directory offset of new block */ int count; /* count of filesystem blocks */ int error; |
1da177e4c Linux-2.6.12-rc2 |
504 |
|
0b1b213fc xfs: event tracin... |
505 |
trace_xfs_dir2_grow_inode(args, space); |
1da177e4c Linux-2.6.12-rc2 |
506 507 508 509 510 |
/* * Set lowest possible block in the space requested. */ bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE); count = mp->m_dirblkfsbs; |
77936d028 xfs: factor out x... |
511 512 513 |
error = xfs_da_grow_inode_int(args, &bno, count); if (error) |
1da177e4c Linux-2.6.12-rc2 |
514 |
return error; |
a7444053f [XFS] Account for... |
515 |
|
bbaaf5380 [XFS] Reduce shou... |
516 |
*dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); |
a7444053f [XFS] Account for... |
517 |
|
1da177e4c Linux-2.6.12-rc2 |
518 519 520 521 522 523 524 525 526 |
/* * Update file's size if this is the data space and it grew. */ if (space == XFS_DIR2_DATA_SPACE) { xfs_fsize_t size; /* directory file (data) size */ size = XFS_FSB_TO_B(mp, bno + count); if (size > dp->i_d.di_size) { dp->i_d.di_size = size; |
77936d028 xfs: factor out x... |
527 |
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); |
1da177e4c Linux-2.6.12-rc2 |
528 529 530 531 532 533 534 535 |
} } return 0; } /* * See if the directory is a single-block form directory. */ |
f6c2d1fa6 [XFS] Remove vers... |
536 |
int |
1da177e4c Linux-2.6.12-rc2 |
537 |
xfs_dir2_isblock( |
f6c2d1fa6 [XFS] Remove vers... |
538 539 |
xfs_trans_t *tp, xfs_inode_t *dp, |
1da177e4c Linux-2.6.12-rc2 |
540 541 542 |
int *vp) /* out: 1 is block, 0 is not block */ { xfs_fileoff_t last; /* last file offset */ |
f6c2d1fa6 [XFS] Remove vers... |
543 544 |
xfs_mount_t *mp; int rval; |
1da177e4c Linux-2.6.12-rc2 |
545 546 |
mp = dp->i_mount; |
f6c2d1fa6 [XFS] Remove vers... |
547 |
if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) |
1da177e4c Linux-2.6.12-rc2 |
548 |
return rval; |
1da177e4c Linux-2.6.12-rc2 |
549 550 551 552 553 554 555 556 557 |
rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize; ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize); *vp = rval; return 0; } /* * See if the directory is a single-leaf form directory. */ |
f6c2d1fa6 [XFS] Remove vers... |
558 |
int |
1da177e4c Linux-2.6.12-rc2 |
559 |
xfs_dir2_isleaf( |
f6c2d1fa6 [XFS] Remove vers... |
560 561 |
xfs_trans_t *tp, xfs_inode_t *dp, |
1da177e4c Linux-2.6.12-rc2 |
562 563 564 |
int *vp) /* out: 1 is leaf, 0 is not leaf */ { xfs_fileoff_t last; /* last file offset */ |
f6c2d1fa6 [XFS] Remove vers... |
565 566 |
xfs_mount_t *mp; int rval; |
1da177e4c Linux-2.6.12-rc2 |
567 568 |
mp = dp->i_mount; |
f6c2d1fa6 [XFS] Remove vers... |
569 |
if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) |
1da177e4c Linux-2.6.12-rc2 |
570 |
return rval; |
1da177e4c Linux-2.6.12-rc2 |
571 572 573 574 575 |
*vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog); return 0; } /* |
1da177e4c Linux-2.6.12-rc2 |
576 577 578 579 580 581 |
* Remove the given block from the directory. * This routine is used for data and free blocks, leaf/node are done * by xfs_da_shrink_inode. */ int xfs_dir2_shrink_inode( |
f6c2d1fa6 [XFS] Remove vers... |
582 583 584 |
xfs_da_args_t *args, xfs_dir2_db_t db, xfs_dabuf_t *bp) |
1da177e4c Linux-2.6.12-rc2 |
585 586 587 588 |
{ xfs_fileoff_t bno; /* directory file offset */ xfs_dablk_t da; /* directory file offset */ int done; /* bunmap is finished */ |
f6c2d1fa6 [XFS] Remove vers... |
589 590 591 592 |
xfs_inode_t *dp; int error; xfs_mount_t *mp; xfs_trans_t *tp; |
1da177e4c Linux-2.6.12-rc2 |
593 |
|
0b1b213fc xfs: event tracin... |
594 |
trace_xfs_dir2_shrink_inode(args, db); |
1da177e4c Linux-2.6.12-rc2 |
595 596 597 |
dp = args->dp; mp = dp->i_mount; tp = args->trans; |
bbaaf5380 [XFS] Reduce shou... |
598 |
da = xfs_dir2_db_to_da(mp, db); |
1da177e4c Linux-2.6.12-rc2 |
599 600 601 602 603 |
/* * Unmap the fsblock(s). */ if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs, XFS_BMAPI_METADATA, 0, args->firstblock, args->flist, |
b4e9181e7 xfs: remove unuse... |
604 |
&done))) { |
1da177e4c Linux-2.6.12-rc2 |
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 |
/* * ENOSPC actually can happen if we're in a removename with * no space reservation, and the resulting block removal * would cause a bmap btree split or conversion from extents * to btree. This can only happen for un-fragmented * directory blocks, since you need to be punching out * the middle of an extent. * In this case we need to leave the block in the file, * and not binval it. * So the block has to be in a consistent empty state * and appropriately logged. * We don't free up the buffer, the caller can tell it * hasn't happened since it got an error back. */ return error; } ASSERT(done); /* * Invalidate the buffer from the transaction. */ xfs_da_binval(tp, bp); /* * If it's not a data block, we're done. */ if (db >= XFS_DIR2_LEAF_FIRSTDB(mp)) return 0; /* * If the block isn't the last one in the directory, we're done. */ |
bbaaf5380 [XFS] Reduce shou... |
634 |
if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(mp, db + 1, 0)) |
1da177e4c Linux-2.6.12-rc2 |
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 |
return 0; bno = da; if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) { /* * This can't really happen unless there's kernel corruption. */ return error; } if (db == mp->m_dirdatablk) ASSERT(bno == 0); else ASSERT(bno > 0); /* * Set the size to the new last block. */ dp->i_d.di_size = XFS_FSB_TO_B(mp, bno); xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); return 0; } |