diff options
Diffstat (limited to 'fs/xfs/xfs_dir2.c')
| -rw-r--r-- | fs/xfs/xfs_dir2.c | 342 | 
1 files changed, 212 insertions, 130 deletions
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index ce16ef02997a..fda46253966a 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c  | |||
| @@ -180,16 +180,23 @@ xfs_dir_init( | |||
| 180 | xfs_inode_t *dp, | 180 | xfs_inode_t *dp, | 
| 181 | xfs_inode_t *pdp) | 181 | xfs_inode_t *pdp) | 
| 182 | { | 182 | { | 
| 183 | xfs_da_args_t args; | 183 | struct xfs_da_args *args; | 
| 184 | int error; | 184 | int error; | 
| 185 | 185 | ||
| 186 | memset((char *)&args, 0, sizeof(args)); | ||
| 187 | args.dp = dp; | ||
| 188 | args.trans = tp; | ||
| 189 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 186 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 
| 190 | if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) | 187 | error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino); | 
| 188 | if (error) | ||
| 191 | return error; | 189 | return error; | 
| 192 | return xfs_dir2_sf_create(&args, pdp->i_ino); | 190 | |
| 191 | args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); | ||
| 192 | if (!args) | ||
| 193 | return ENOMEM; | ||
| 194 | |||
| 195 | args->dp = dp; | ||
| 196 | args->trans = tp; | ||
| 197 | error = xfs_dir2_sf_create(args, pdp->i_ino); | ||
| 198 | kmem_free(args); | ||
| 199 | return error; | ||
| 193 | } | 200 | } | 
| 194 | 201 | ||
| 195 | /* | 202 | /* | 
| @@ -205,41 +212,56 @@ xfs_dir_createname( | |||
| 205 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ | 212 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ | 
| 206 | xfs_extlen_t total) /* bmap's total block count */ | 213 | xfs_extlen_t total) /* bmap's total block count */ | 
| 207 | { | 214 | { | 
| 208 | xfs_da_args_t args; | 215 | struct xfs_da_args *args; | 
| 209 | int rval; | 216 | int rval; | 
| 210 | int v; /* type-checking value */ | 217 | int v; /* type-checking value */ | 
| 211 | 218 | ||
| 212 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 219 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 
| 213 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) | 220 | rval = xfs_dir_ino_validate(tp->t_mountp, inum); | 
| 221 | if (rval) | ||
| 214 | return rval; | 222 | return rval; | 
| 215 | XFS_STATS_INC(xs_dir_create); | 223 | XFS_STATS_INC(xs_dir_create); | 
| 216 | 224 | ||
| 217 | memset(&args, 0, sizeof(xfs_da_args_t)); | 225 | args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); | 
| 218 | args.name = name->name; | 226 | if (!args) | 
| 219 | args.namelen = name->len; | 227 | return ENOMEM; | 
| 220 | args.filetype = name->type; | 228 | |
| 221 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); | 229 | args->name = name->name; | 
| 222 | args.inumber = inum; | 230 | args->namelen = name->len; | 
| 223 | args.dp = dp; | 231 | args->filetype = name->type; | 
| 224 | args.firstblock = first; | 232 | args->hashval = dp->i_mount->m_dirnameops->hashname(name); | 
| 225 | args.flist = flist; | 233 | args->inumber = inum; | 
| 226 | args.total = total; | 234 | args->dp = dp; | 
| 227 | args.whichfork = XFS_DATA_FORK; | 235 | args->firstblock = first; | 
| 228 | args.trans = tp; | 236 | args->flist = flist; | 
| 229 | args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; | 237 | args->total = total; | 
| 230 | 238 | args->whichfork = XFS_DATA_FORK; | |
| 231 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 239 | args->trans = tp; | 
| 232 | rval = xfs_dir2_sf_addname(&args); | 240 | args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; | 
| 233 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) | 241 | |
| 234 | return rval; | 242 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | 
| 235 | else if (v) | 243 | rval = xfs_dir2_sf_addname(args); | 
| 236 | rval = xfs_dir2_block_addname(&args); | 244 | goto out_free; | 
| 237 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) | 245 | } | 
| 238 | return rval; | 246 | |
| 239 | else if (v) | 247 | rval = xfs_dir2_isblock(tp, dp, &v); | 
| 240 | rval = xfs_dir2_leaf_addname(&args); | 248 | if (rval) | 
| 249 | goto out_free; | ||
| 250 | if (v) { | ||
| 251 | rval = xfs_dir2_block_addname(args); | ||
| 252 | goto out_free; | ||
| 253 | } | ||
| 254 | |||
| 255 | rval = xfs_dir2_isleaf(tp, dp, &v); | ||
| 256 | if (rval) | ||
| 257 | goto out_free; | ||
| 258 | if (v) | ||
| 259 | rval = xfs_dir2_leaf_addname(args); | ||
| 241 | else | 260 | else | 
| 242 | rval = xfs_dir2_node_addname(&args); | 261 | rval = xfs_dir2_node_addname(args); | 
| 262 | |||
| 263 | out_free: | ||
| 264 | kmem_free(args); | ||
| 243 | return rval; | 265 | return rval; | 
| 244 | } | 266 | } | 
| 245 | 267 | ||
| @@ -282,46 +304,66 @@ xfs_dir_lookup( | |||
| 282 | xfs_ino_t *inum, /* out: inode number */ | 304 | xfs_ino_t *inum, /* out: inode number */ | 
| 283 | struct xfs_name *ci_name) /* out: actual name if CI match */ | 305 | struct xfs_name *ci_name) /* out: actual name if CI match */ | 
| 284 | { | 306 | { | 
| 285 | xfs_da_args_t args; | 307 | struct xfs_da_args *args; | 
| 286 | int rval; | 308 | int rval; | 
| 287 | int v; /* type-checking value */ | 309 | int v; /* type-checking value */ | 
| 288 | 310 | ||
| 289 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 311 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 
| 290 | XFS_STATS_INC(xs_dir_lookup); | 312 | XFS_STATS_INC(xs_dir_lookup); | 
| 291 | 313 | ||
| 292 | memset(&args, 0, sizeof(xfs_da_args_t)); | 314 | /* | 
| 293 | args.name = name->name; | 315 | * We need to use KM_NOFS here so that lockdep will not throw false | 
| 294 | args.namelen = name->len; | 316 | * positive deadlock warnings on a non-transactional lookup path. It is | 
| 295 | args.filetype = name->type; | 317 | * safe to recurse into inode recalim in that case, but lockdep can't | 
| 296 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); | 318 | * easily be taught about it. Hence KM_NOFS avoids having to add more | 
| 297 | args.dp = dp; | 319 | * lockdep Doing this avoids having to add a bunch of lockdep class | 
| 298 | args.whichfork = XFS_DATA_FORK; | 320 | * annotations into the reclaim path for the ilock. | 
| 299 | args.trans = tp; | 321 | */ | 
| 300 | args.op_flags = XFS_DA_OP_OKNOENT; | 322 | args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); | 
| 323 | args->name = name->name; | ||
| 324 | args->namelen = name->len; | ||
| 325 | args->filetype = name->type; | ||
| 326 | args->hashval = dp->i_mount->m_dirnameops->hashname(name); | ||
| 327 | args->dp = dp; | ||
| 328 | args->whichfork = XFS_DATA_FORK; | ||
| 329 | args->trans = tp; | ||
| 330 | args->op_flags = XFS_DA_OP_OKNOENT; | ||
| 301 | if (ci_name) | 331 | if (ci_name) | 
| 302 | args.op_flags |= XFS_DA_OP_CILOOKUP; | 332 | args->op_flags |= XFS_DA_OP_CILOOKUP; | 
| 303 | 333 | ||
| 304 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 334 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | 
| 305 | rval = xfs_dir2_sf_lookup(&args); | 335 | rval = xfs_dir2_sf_lookup(args); | 
| 306 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) | 336 | goto out_check_rval; | 
| 307 | return rval; | 337 | } | 
| 308 | else if (v) | 338 | |
| 309 | rval = xfs_dir2_block_lookup(&args); | 339 | rval = xfs_dir2_isblock(tp, dp, &v); | 
| 310 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) | 340 | if (rval) | 
| 311 | return rval; | 341 | goto out_free; | 
| 312 | else if (v) | 342 | if (v) { | 
| 313 | rval = xfs_dir2_leaf_lookup(&args); | 343 | rval = xfs_dir2_block_lookup(args); | 
| 344 | goto out_check_rval; | ||
| 345 | } | ||
| 346 | |||
| 347 | rval = xfs_dir2_isleaf(tp, dp, &v); | ||
| 348 | if (rval) | ||
| 349 | goto out_free; | ||
| 350 | if (v) | ||
| 351 | rval = xfs_dir2_leaf_lookup(args); | ||
| 314 | else | 352 | else | 
| 315 | rval = xfs_dir2_node_lookup(&args); | 353 | rval = xfs_dir2_node_lookup(args); | 
| 354 | |||
| 355 | out_check_rval: | ||
| 316 | if (rval == EEXIST) | 356 | if (rval == EEXIST) | 
| 317 | rval = 0; | 357 | rval = 0; | 
| 318 | if (!rval) { | 358 | if (!rval) { | 
| 319 | *inum = args.inumber; | 359 | *inum = args->inumber; | 
| 320 | if (ci_name) { | 360 | if (ci_name) { | 
| 321 | ci_name->name = args.value; | 361 | ci_name->name = args->value; | 
| 322 | ci_name->len = args.valuelen; | 362 | ci_name->len = args->valuelen; | 
| 323 | } | 363 | } | 
| 324 | } | 364 | } | 
| 365 | out_free: | ||
| 366 | kmem_free(args); | ||
| 325 | return rval; | 367 | return rval; | 
| 326 | } | 368 | } | 
| 327 | 369 | ||
| @@ -338,38 +380,51 @@ xfs_dir_removename( | |||
| 338 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ | 380 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ | 
| 339 | xfs_extlen_t total) /* bmap's total block count */ | 381 | xfs_extlen_t total) /* bmap's total block count */ | 
| 340 | { | 382 | { | 
| 341 | xfs_da_args_t args; | 383 | struct xfs_da_args *args; | 
| 342 | int rval; | 384 | int rval; | 
| 343 | int v; /* type-checking value */ | 385 | int v; /* type-checking value */ | 
| 344 | 386 | ||
| 345 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 387 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 
| 346 | XFS_STATS_INC(xs_dir_remove); | 388 | XFS_STATS_INC(xs_dir_remove); | 
| 347 | 389 | ||
| 348 | memset(&args, 0, sizeof(xfs_da_args_t)); | 390 | args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); | 
| 349 | args.name = name->name; | 391 | if (!args) | 
| 350 | args.namelen = name->len; | 392 | return ENOMEM; | 
| 351 | args.filetype = name->type; | 393 | |
| 352 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); | 394 | args->name = name->name; | 
| 353 | args.inumber = ino; | 395 | args->namelen = name->len; | 
| 354 | args.dp = dp; | 396 | args->filetype = name->type; | 
| 355 | args.firstblock = first; | 397 | args->hashval = dp->i_mount->m_dirnameops->hashname(name); | 
| 356 | args.flist = flist; | 398 | args->inumber = ino; | 
| 357 | args.total = total; | 399 | args->dp = dp; | 
| 358 | args.whichfork = XFS_DATA_FORK; | 400 | args->firstblock = first; | 
| 359 | args.trans = tp; | 401 | args->flist = flist; | 
| 360 | 402 | args->total = total; | |
| 361 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 403 | args->whichfork = XFS_DATA_FORK; | 
| 362 | rval = xfs_dir2_sf_removename(&args); | 404 | args->trans = tp; | 
| 363 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) | 405 | |
| 364 | return rval; | 406 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | 
| 365 | else if (v) | 407 | rval = xfs_dir2_sf_removename(args); | 
| 366 | rval = xfs_dir2_block_removename(&args); | 408 | goto out_free; | 
| 367 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) | 409 | } | 
| 368 | return rval; | 410 | |
| 369 | else if (v) | 411 | rval = xfs_dir2_isblock(tp, dp, &v); | 
| 370 | rval = xfs_dir2_leaf_removename(&args); | 412 | if (rval) | 
| 413 | goto out_free; | ||
| 414 | if (v) { | ||
| 415 | rval = xfs_dir2_block_removename(args); | ||
| 416 | goto out_free; | ||
| 417 | } | ||
| 418 | |||
| 419 | rval = xfs_dir2_isleaf(tp, dp, &v); | ||
| 420 | if (rval) | ||
| 421 | goto out_free; | ||
| 422 | if (v) | ||
| 423 | rval = xfs_dir2_leaf_removename(args); | ||
| 371 | else | 424 | else | 
| 372 | rval = xfs_dir2_node_removename(&args); | 425 | rval = xfs_dir2_node_removename(args); | 
| 426 | out_free: | ||
| 427 | kmem_free(args); | ||
| 373 | return rval; | 428 | return rval; | 
| 374 | } | 429 | } | 
| 375 | 430 | ||
| @@ -386,40 +441,54 @@ xfs_dir_replace( | |||
| 386 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ | 441 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ | 
| 387 | xfs_extlen_t total) /* bmap's total block count */ | 442 | xfs_extlen_t total) /* bmap's total block count */ | 
| 388 | { | 443 | { | 
| 389 | xfs_da_args_t args; | 444 | struct xfs_da_args *args; | 
| 390 | int rval; | 445 | int rval; | 
| 391 | int v; /* type-checking value */ | 446 | int v; /* type-checking value */ | 
| 392 | 447 | ||
| 393 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 448 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 
| 394 | 449 | ||
| 395 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) | 450 | rval = xfs_dir_ino_validate(tp->t_mountp, inum); | 
| 451 | if (rval) | ||
| 396 | return rval; | 452 | return rval; | 
| 397 | 453 | ||
| 398 | memset(&args, 0, sizeof(xfs_da_args_t)); | 454 | args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); | 
| 399 | args.name = name->name; | 455 | if (!args) | 
| 400 | args.namelen = name->len; | 456 | return ENOMEM; | 
| 401 | args.filetype = name->type; | 457 | |
| 402 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); | 458 | args->name = name->name; | 
| 403 | args.inumber = inum; | 459 | args->namelen = name->len; | 
| 404 | args.dp = dp; | 460 | args->filetype = name->type; | 
| 405 | args.firstblock = first; | 461 | args->hashval = dp->i_mount->m_dirnameops->hashname(name); | 
| 406 | args.flist = flist; | 462 | args->inumber = inum; | 
| 407 | args.total = total; | 463 | args->dp = dp; | 
| 408 | args.whichfork = XFS_DATA_FORK; | 464 | args->firstblock = first; | 
| 409 | args.trans = tp; | 465 | args->flist = flist; | 
| 410 | 466 | args->total = total; | |
| 411 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 467 | args->whichfork = XFS_DATA_FORK; | 
| 412 | rval = xfs_dir2_sf_replace(&args); | 468 | args->trans = tp; | 
| 413 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) | 469 | |
| 414 | return rval; | 470 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | 
| 415 | else if (v) | 471 | rval = xfs_dir2_sf_replace(args); | 
| 416 | rval = xfs_dir2_block_replace(&args); | 472 | goto out_free; | 
| 417 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) | 473 | } | 
| 418 | return rval; | 474 | |
| 419 | else if (v) | 475 | rval = xfs_dir2_isblock(tp, dp, &v); | 
| 420 | rval = xfs_dir2_leaf_replace(&args); | 476 | if (rval) | 
| 477 | goto out_free; | ||
| 478 | if (v) { | ||
| 479 | rval = xfs_dir2_block_replace(args); | ||
| 480 | goto out_free; | ||
| 481 | } | ||
| 482 | |||
| 483 | rval = xfs_dir2_isleaf(tp, dp, &v); | ||
| 484 | if (rval) | ||
| 485 | goto out_free; | ||
| 486 | if (v) | ||
| 487 | rval = xfs_dir2_leaf_replace(args); | ||
| 421 | else | 488 | else | 
| 422 | rval = xfs_dir2_node_replace(&args); | 489 | rval = xfs_dir2_node_replace(args); | 
| 490 | out_free: | ||
| 491 | kmem_free(args); | ||
| 423 | return rval; | 492 | return rval; | 
| 424 | } | 493 | } | 
| 425 | 494 | ||
| @@ -434,7 +503,7 @@ xfs_dir_canenter( | |||
| 434 | struct xfs_name *name, /* name of entry to add */ | 503 | struct xfs_name *name, /* name of entry to add */ | 
| 435 | uint resblks) | 504 | uint resblks) | 
| 436 | { | 505 | { | 
| 437 | xfs_da_args_t args; | 506 | struct xfs_da_args *args; | 
| 438 | int rval; | 507 | int rval; | 
| 439 | int v; /* type-checking value */ | 508 | int v; /* type-checking value */ | 
| 440 | 509 | ||
| @@ -443,29 +512,42 @@ xfs_dir_canenter( | |||
| 443 | 512 | ||
| 444 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 513 | ASSERT(S_ISDIR(dp->i_d.di_mode)); | 
| 445 | 514 | ||
| 446 | memset(&args, 0, sizeof(xfs_da_args_t)); | 515 | args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); | 
| 447 | args.name = name->name; | 516 | if (!args) | 
| 448 | args.namelen = name->len; | 517 | return ENOMEM; | 
| 449 | args.filetype = name->type; | 518 | |
| 450 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); | 519 | args->name = name->name; | 
| 451 | args.dp = dp; | 520 | args->namelen = name->len; | 
| 452 | args.whichfork = XFS_DATA_FORK; | 521 | args->filetype = name->type; | 
| 453 | args.trans = tp; | 522 | args->hashval = dp->i_mount->m_dirnameops->hashname(name); | 
| 454 | args.op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME | | 523 | args->dp = dp; | 
| 524 | args->whichfork = XFS_DATA_FORK; | ||
| 525 | args->trans = tp; | ||
| 526 | args->op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME | | ||
| 455 | XFS_DA_OP_OKNOENT; | 527 | XFS_DA_OP_OKNOENT; | 
| 456 | 528 | ||
| 457 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 529 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | 
| 458 | rval = xfs_dir2_sf_addname(&args); | 530 | rval = xfs_dir2_sf_addname(args); | 
| 459 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) | 531 | goto out_free; | 
| 460 | return rval; | 532 | } | 
| 461 | else if (v) | 533 | |
| 462 | rval = xfs_dir2_block_addname(&args); | 534 | rval = xfs_dir2_isblock(tp, dp, &v); | 
| 463 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) | 535 | if (rval) | 
| 464 | return rval; | 536 | goto out_free; | 
| 465 | else if (v) | 537 | if (v) { | 
| 466 | rval = xfs_dir2_leaf_addname(&args); | 538 | rval = xfs_dir2_block_addname(args); | 
| 539 | goto out_free; | ||
| 540 | } | ||
| 541 | |||
| 542 | rval = xfs_dir2_isleaf(tp, dp, &v); | ||
| 543 | if (rval) | ||
| 544 | goto out_free; | ||
| 545 | if (v) | ||
| 546 | rval = xfs_dir2_leaf_addname(args); | ||
| 467 | else | 547 | else | 
| 468 | rval = xfs_dir2_node_addname(&args); | 548 | rval = xfs_dir2_node_addname(args); | 
| 549 | out_free: | ||
| 550 | kmem_free(args); | ||
| 469 | return rval; | 551 | return rval; | 
| 470 | } | 552 | } | 
| 471 | 553 | ||
