@@ -356,7 +356,7 @@ void bch2_data_update_exit(struct data_update *update)
356356 bch2_bio_free_pages_pool (c , & update -> op .wbio .bio );
357357}
358358
359- void bch2_update_unwritten_extent (struct btree_trans * trans ,
359+ static void bch2_update_unwritten_extent (struct btree_trans * trans ,
360360 struct data_update * update )
361361{
362362 struct bch_fs * c = update -> op .c ;
@@ -436,7 +436,51 @@ void bch2_update_unwritten_extent(struct btree_trans *trans,
436436 }
437437}
438438
439+ int bch2_extent_drop_ptrs (struct btree_trans * trans ,
440+ struct btree_iter * iter ,
441+ struct bkey_s_c k ,
442+ struct data_update_opts data_opts )
443+ {
444+ struct bch_fs * c = trans -> c ;
445+ struct bkey_i * n ;
446+ int ret ;
447+
448+ n = bch2_bkey_make_mut_noupdate (trans , k );
449+ ret = PTR_ERR_OR_ZERO (n );
450+ if (ret )
451+ return ret ;
452+
453+ while (data_opts .kill_ptrs ) {
454+ unsigned i = 0 , drop = __fls (data_opts .kill_ptrs );
455+ struct bch_extent_ptr * ptr ;
456+
457+ bch2_bkey_drop_ptrs (bkey_i_to_s (n ), ptr , i ++ == drop );
458+ data_opts .kill_ptrs ^= 1U << drop ;
459+ }
460+
461+ /*
462+ * If the new extent no longer has any pointers, bch2_extent_normalize()
463+ * will do the appropriate thing with it (turning it into a
464+ * KEY_TYPE_error key, or just a discard if it was a cached extent)
465+ */
466+ bch2_extent_normalize (c , bkey_i_to_s (n ));
467+
468+ /*
469+ * Since we're not inserting through an extent iterator
470+ * (BTREE_ITER_ALL_SNAPSHOTS iterators aren't extent iterators),
471+ * we aren't using the extent overwrite path to delete, we're
472+ * just using the normal key deletion path:
473+ */
474+ if (bkey_deleted (& n -> k ))
475+ n -> k .size = 0 ;
476+
477+ return bch2_trans_relock (trans ) ?:
478+ bch2_trans_update (trans , iter , n , BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE ) ?:
479+ bch2_trans_commit (trans , NULL , NULL , BTREE_INSERT_NOFAIL );
480+ }
481+
439482int bch2_data_update_init (struct btree_trans * trans ,
483+ struct btree_iter * iter ,
440484 struct moving_context * ctxt ,
441485 struct data_update * m ,
442486 struct write_point_specifier wp ,
@@ -452,7 +496,7 @@ int bch2_data_update_init(struct btree_trans *trans,
452496 const struct bch_extent_ptr * ptr ;
453497 unsigned i , reserve_sectors = k .k -> size * data_opts .extra_replicas ;
454498 unsigned ptrs_locked = 0 ;
455- int ret ;
499+ int ret = 0 ;
456500
457501 bch2_bkey_buf_init (& m -> k );
458502 bch2_bkey_buf_reassemble (& m -> k , c , k );
@@ -478,6 +522,8 @@ int bch2_data_update_init(struct btree_trans *trans,
478522 bkey_for_each_ptr (ptrs , ptr )
479523 percpu_ref_get (& bch_dev_bkey_exists (c , ptr -> dev )-> ref );
480524
525+ unsigned durability_have = 0 , durability_removing = 0 ;
526+
481527 i = 0 ;
482528 bkey_for_each_ptr_decode (k .k , ptrs , p , entry ) {
483529 bool locked ;
@@ -489,8 +535,11 @@ int bch2_data_update_init(struct btree_trans *trans,
489535 reserve_sectors += k .k -> size ;
490536
491537 m -> op .nr_replicas += bch2_extent_ptr_desired_durability (c , & p );
492- } else if (!p .ptr .cached ) {
538+ durability_removing += bch2_extent_ptr_desired_durability (c , & p );
539+ } else if (!p .ptr .cached &&
540+ !((1U << i ) & m -> data_opts .kill_ptrs )) {
493541 bch2_dev_list_add_dev (& m -> op .devs_have , p .ptr .dev );
542+ durability_have += bch2_extent_ptr_durability (c , & p );
494543 }
495544
496545 /*
@@ -529,6 +578,29 @@ int bch2_data_update_init(struct btree_trans *trans,
529578 i ++ ;
530579 }
531580
581+ /*
582+ * If current extent durability is less than io_opts.data_replicas,
583+ * we're not trying to rereplicate the extent up to data_replicas here -
584+ * unless extra_replicas was specified
585+ *
586+ * Increasing replication is an explicit operation triggered by
587+ * rereplicate, currently, so that users don't get an unexpected -ENOSPC
588+ */
589+ if (durability_have >= io_opts .data_replicas ) {
590+ m -> data_opts .kill_ptrs |= m -> data_opts .rewrite_ptrs ;
591+ m -> data_opts .rewrite_ptrs = 0 ;
592+ /* if iter == NULL, it's just a promote */
593+ if (iter )
594+ ret = bch2_extent_drop_ptrs (trans , iter , k , data_opts );
595+ goto done ;
596+ }
597+
598+ m -> op .nr_replicas = min (durability_removing , io_opts .data_replicas - durability_have ) +
599+ m -> data_opts .extra_replicas ;
600+ m -> op .nr_replicas_required = m -> op .nr_replicas ;
601+
602+ BUG_ON (!m -> op .nr_replicas );
603+
532604 if (reserve_sectors ) {
533605 ret = bch2_disk_reservation_add (c , & m -> op .res , reserve_sectors ,
534606 m -> data_opts .extra_replicas
@@ -538,14 +610,11 @@ int bch2_data_update_init(struct btree_trans *trans,
538610 goto err ;
539611 }
540612
541- m -> op . nr_replicas += m -> data_opts . extra_replicas ;
542- m -> op . nr_replicas_required = m -> op . nr_replicas ;
543-
544- BUG_ON (! m -> op . nr_replicas );
613+ if ( bkey_extent_is_unwritten ( k )) {
614+ bch2_update_unwritten_extent ( trans , m ) ;
615+ goto done ;
616+ }
545617
546- /* Special handling required: */
547- if (bkey_extent_is_unwritten (k ))
548- return - BCH_ERR_unwritten_extent_update ;
549618 return 0 ;
550619err :
551620 i = 0 ;
@@ -560,6 +629,9 @@ int bch2_data_update_init(struct btree_trans *trans,
560629 bch2_bkey_buf_exit (& m -> k , c );
561630 bch2_bio_free_pages_pool (c , & m -> op .wbio .bio );
562631 return ret ;
632+ done :
633+ bch2_data_update_exit (m );
634+ return ret ?: - BCH_ERR_data_update_done ;
563635}
564636
565637void bch2_data_update_opts_normalize (struct bkey_s_c k , struct data_update_opts * opts )
0 commit comments