@@ -245,7 +245,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
245
245
union afs_xdr_dir_block * meta , * block ;
246
246
union afs_xdr_dirent * de ;
247
247
struct afs_dir_iter iter = { .dvnode = vnode };
248
- unsigned int need_slots , nr_blocks , b ;
248
+ unsigned int nr_blocks , b , entry ;
249
249
loff_t i_size ;
250
250
int slot ;
251
251
@@ -263,7 +263,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
263
263
return ;
264
264
265
265
/* Work out how many slots we're going to need. */
266
- need_slots = afs_dir_calc_slots (name -> len );
266
+ iter . nr_slots = afs_dir_calc_slots (name -> len );
267
267
268
268
if (i_size == 0 )
269
269
goto new_directory ;
@@ -281,7 +281,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
281
281
282
282
/* Lower dir blocks have a counter in the header we can check. */
283
283
if (b < AFS_DIR_BLOCKS_WITH_CTR &&
284
- meta -> meta .alloc_ctrs [b ] < need_slots )
284
+ meta -> meta .alloc_ctrs [b ] < iter . nr_slots )
285
285
continue ;
286
286
287
287
block = afs_dir_get_block (& iter , b );
@@ -308,7 +308,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
308
308
/* We need to try and find one or more consecutive slots to
309
309
* hold the entry.
310
310
*/
311
- slot = afs_find_contig_bits (block , need_slots );
311
+ slot = afs_find_contig_bits (block , iter . nr_slots );
312
312
if (slot >= 0 ) {
313
313
_debug ("slot %u" , slot );
314
314
goto found_space ;
@@ -347,12 +347,18 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
347
347
de -> u .name [name -> len ] = 0 ;
348
348
349
349
/* Adjust the bitmap. */
350
- afs_set_contig_bits (block , slot , need_slots );
351
- kunmap_local (block );
350
+ afs_set_contig_bits (block , slot , iter .nr_slots );
352
351
353
352
/* Adjust the allocation counter. */
354
353
if (b < AFS_DIR_BLOCKS_WITH_CTR )
355
- meta -> meta .alloc_ctrs [b ] -= need_slots ;
354
+ meta -> meta .alloc_ctrs [b ] -= iter .nr_slots ;
355
+
356
+ /* Adjust the hash chain. */
357
+ entry = b * AFS_DIR_SLOTS_PER_BLOCK + slot ;
358
+ iter .bucket = afs_dir_hash_name (name );
359
+ de -> u .hash_next = meta -> meta .hashtable [iter .bucket ];
360
+ meta -> meta .hashtable [iter .bucket ] = htons (entry );
361
+ kunmap_local (block );
356
362
357
363
inode_inc_iversion_raw (& vnode -> netfs .inode );
358
364
afs_stat_v (vnode , n_dir_cr );
@@ -387,12 +393,14 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
387
393
void afs_edit_dir_remove (struct afs_vnode * vnode ,
388
394
struct qstr * name , enum afs_edit_dir_reason why )
389
395
{
390
- union afs_xdr_dir_block * meta , * block ;
391
- union afs_xdr_dirent * de ;
396
+ union afs_xdr_dir_block * meta , * block , * pblock ;
397
+ union afs_xdr_dirent * de , * pde ;
392
398
struct afs_dir_iter iter = { .dvnode = vnode };
393
- unsigned int need_slots , nr_blocks , b ;
399
+ struct afs_fid fid ;
400
+ unsigned int b , slot , entry ;
394
401
loff_t i_size ;
395
- int slot ;
402
+ __be16 next ;
403
+ int found ;
396
404
397
405
_enter (",,{%d,%s}," , name -> len , name -> name );
398
406
@@ -403,59 +411,90 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
403
411
afs_invalidate_dir (vnode , afs_dir_invalid_edit_rem_bad_size );
404
412
return ;
405
413
}
406
- nr_blocks = i_size / AFS_DIR_BLOCK_SIZE ;
407
414
408
- meta = afs_dir_get_block (& iter , 0 );
409
- if (!meta )
415
+ if (!afs_dir_init_iter (& iter , name ))
410
416
return ;
411
417
412
- /* Work out how many slots we're going to discard. */
413
- need_slots = afs_dir_calc_slots (name -> len );
414
-
415
- /* Find a block that has sufficient slots available. Each folio
416
- * contains two or more directory blocks.
417
- */
418
- for (b = 0 ; b < nr_blocks ; b ++ ) {
419
- block = afs_dir_get_block (& iter , b );
420
- if (!block )
421
- goto error ;
422
-
423
- /* Abandon the edit if we got a callback break. */
424
- if (!test_bit (AFS_VNODE_DIR_VALID , & vnode -> flags ))
425
- goto already_invalidated ;
426
-
427
- if (b > AFS_DIR_BLOCKS_WITH_CTR ||
428
- meta -> meta .alloc_ctrs [b ] <= AFS_DIR_SLOTS_PER_BLOCK - 1 - need_slots ) {
429
- slot = afs_dir_scan_block (block , name , b );
430
- if (slot >= 0 )
431
- goto found_dirent ;
432
- }
418
+ meta = afs_dir_find_block (& iter , 0 );
419
+ if (!meta )
420
+ return ;
433
421
434
- kunmap_local (block );
422
+ /* Find the entry in the blob. */
423
+ found = afs_dir_search_bucket (& iter , name , & fid );
424
+ if (found < 0 ) {
425
+ /* Didn't find the dirent to clobber. Re-download. */
426
+ trace_afs_edit_dir (vnode , why , afs_edit_dir_delete_noent ,
427
+ 0 , 0 , 0 , 0 , name -> name );
428
+ afs_invalidate_dir (vnode , afs_dir_invalid_edit_rem_wrong_name );
429
+ goto out_unmap ;
435
430
}
436
431
437
- /* Didn't find the dirent to clobber. Download the directory again. */
438
- trace_afs_edit_dir (vnode , why , afs_edit_dir_delete_noent ,
439
- 0 , 0 , 0 , 0 , name -> name );
440
- afs_invalidate_dir (vnode , afs_dir_invalid_edit_rem_wrong_name );
441
- goto out_unmap ;
432
+ entry = found ;
433
+ b = entry / AFS_DIR_SLOTS_PER_BLOCK ;
434
+ slot = entry % AFS_DIR_SLOTS_PER_BLOCK ;
442
435
443
- found_dirent :
436
+ block = afs_dir_find_block (& iter , b );
437
+ if (!block )
438
+ goto error ;
439
+ if (!test_bit (AFS_VNODE_DIR_VALID , & vnode -> flags ))
440
+ goto already_invalidated ;
441
+
442
+ /* Check and clear the entry. */
444
443
de = & block -> dirents [slot ];
444
+ if (de -> u .valid != 1 )
445
+ goto error_unmap ;
445
446
446
447
trace_afs_edit_dir (vnode , why , afs_edit_dir_delete , b , slot ,
447
448
ntohl (de -> u .vnode ), ntohl (de -> u .unique ),
448
449
name -> name );
449
450
450
- memset (de , 0 , sizeof (* de ) * need_slots );
451
-
452
451
/* Adjust the bitmap. */
453
- afs_clear_contig_bits (block , slot , need_slots );
454
- kunmap_local (block );
452
+ afs_clear_contig_bits (block , slot , iter .nr_slots );
455
453
456
454
/* Adjust the allocation counter. */
457
455
if (b < AFS_DIR_BLOCKS_WITH_CTR )
458
- meta -> meta .alloc_ctrs [b ] += need_slots ;
456
+ meta -> meta .alloc_ctrs [b ] += iter .nr_slots ;
457
+
458
+ /* Clear the constituent entries. */
459
+ next = de -> u .hash_next ;
460
+ memset (de , 0 , sizeof (* de ) * iter .nr_slots );
461
+ kunmap_local (block );
462
+
463
+ /* Adjust the hash chain: if iter->prev_entry is 0, the hashtable head
464
+ * index is previous; otherwise it's slot number of the previous entry.
465
+ */
466
+ if (!iter .prev_entry ) {
467
+ __be16 prev_next = meta -> meta .hashtable [iter .bucket ];
468
+
469
+ if (unlikely (prev_next != htons (entry ))) {
470
+ pr_warn ("%llx:%llx:%x: not head of chain b=%x p=%x,%x e=%x %*s" ,
471
+ vnode -> fid .vid , vnode -> fid .vnode , vnode -> fid .unique ,
472
+ iter .bucket , iter .prev_entry , prev_next , entry ,
473
+ name -> len , name -> name );
474
+ goto error ;
475
+ }
476
+ meta -> meta .hashtable [iter .bucket ] = next ;
477
+ } else {
478
+ unsigned int pb = iter .prev_entry / AFS_DIR_SLOTS_PER_BLOCK ;
479
+ unsigned int ps = iter .prev_entry % AFS_DIR_SLOTS_PER_BLOCK ;
480
+ __be16 prev_next ;
481
+
482
+ pblock = afs_dir_find_block (& iter , pb );
483
+ if (!pblock )
484
+ goto error ;
485
+ pde = & pblock -> dirents [ps ];
486
+ prev_next = pde -> u .hash_next ;
487
+ if (prev_next != htons (entry )) {
488
+ kunmap_local (pblock );
489
+ pr_warn ("%llx:%llx:%x: not prev in chain b=%x p=%x,%x e=%x %*s" ,
490
+ vnode -> fid .vid , vnode -> fid .vnode , vnode -> fid .unique ,
491
+ iter .bucket , iter .prev_entry , prev_next , entry ,
492
+ name -> len , name -> name );
493
+ goto error ;
494
+ }
495
+ pde -> u .hash_next = next ;
496
+ kunmap_local (pblock );
497
+ }
459
498
460
499
netfs_single_mark_inode_dirty (& vnode -> netfs .inode );
461
500
@@ -474,6 +513,8 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
474
513
0 , 0 , 0 , 0 , name -> name );
475
514
goto out_unmap ;
476
515
516
+ error_unmap :
517
+ kunmap_local (block );
477
518
error :
478
519
trace_afs_edit_dir (vnode , why , afs_edit_dir_delete_error ,
479
520
0 , 0 , 0 , 0 , name -> name );
0 commit comments