@@ -245,7 +245,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
245245 union afs_xdr_dir_block * meta , * block ;
246246 union afs_xdr_dirent * de ;
247247 struct afs_dir_iter iter = { .dvnode = vnode };
248- unsigned int need_slots , nr_blocks , b ;
248+ unsigned int nr_blocks , b , entry ;
249249 loff_t i_size ;
250250 int slot ;
251251
@@ -263,7 +263,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
263263 return ;
264264
265265 /* 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 );
267267
268268 if (i_size == 0 )
269269 goto new_directory ;
@@ -281,7 +281,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
281281
282282 /* Lower dir blocks have a counter in the header we can check. */
283283 if (b < AFS_DIR_BLOCKS_WITH_CTR &&
284- meta -> meta .alloc_ctrs [b ] < need_slots )
284+ meta -> meta .alloc_ctrs [b ] < iter . nr_slots )
285285 continue ;
286286
287287 block = afs_dir_get_block (& iter , b );
@@ -308,7 +308,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
308308 /* We need to try and find one or more consecutive slots to
309309 * hold the entry.
310310 */
311- slot = afs_find_contig_bits (block , need_slots );
311+ slot = afs_find_contig_bits (block , iter . nr_slots );
312312 if (slot >= 0 ) {
313313 _debug ("slot %u" , slot );
314314 goto found_space ;
@@ -347,12 +347,18 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
347347 de -> u .name [name -> len ] = 0 ;
348348
349349 /* 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 );
352351
353352 /* Adjust the allocation counter. */
354353 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 );
356362
357363 inode_inc_iversion_raw (& vnode -> netfs .inode );
358364 afs_stat_v (vnode , n_dir_cr );
@@ -387,12 +393,14 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
387393void afs_edit_dir_remove (struct afs_vnode * vnode ,
388394 struct qstr * name , enum afs_edit_dir_reason why )
389395{
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 ;
392398 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 ;
394401 loff_t i_size ;
395- int slot ;
402+ __be16 next ;
403+ int found ;
396404
397405 _enter (",,{%d,%s}," , name -> len , name -> name );
398406
@@ -403,59 +411,90 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
403411 afs_invalidate_dir (vnode , afs_dir_invalid_edit_rem_bad_size );
404412 return ;
405413 }
406- nr_blocks = i_size / AFS_DIR_BLOCK_SIZE ;
407414
408- meta = afs_dir_get_block (& iter , 0 );
409- if (!meta )
415+ if (!afs_dir_init_iter (& iter , name ))
410416 return ;
411417
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 ;
433421
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 ;
435430 }
436431
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 ;
442435
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. */
444443 de = & block -> dirents [slot ];
444+ if (de -> u .valid != 1 )
445+ goto error_unmap ;
445446
446447 trace_afs_edit_dir (vnode , why , afs_edit_dir_delete , b , slot ,
447448 ntohl (de -> u .vnode ), ntohl (de -> u .unique ),
448449 name -> name );
449450
450- memset (de , 0 , sizeof (* de ) * need_slots );
451-
452451 /* 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 );
455453
456454 /* Adjust the allocation counter. */
457455 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+ }
459498
460499 netfs_single_mark_inode_dirty (& vnode -> netfs .inode );
461500
@@ -474,6 +513,8 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
474513 0 , 0 , 0 , 0 , name -> name );
475514 goto out_unmap ;
476515
516+ error_unmap :
517+ kunmap_local (block );
477518error :
478519 trace_afs_edit_dir (vnode , why , afs_edit_dir_delete_error ,
479520 0 , 0 , 0 , 0 , name -> name );
0 commit comments