@@ -157,6 +157,20 @@ static bool subvol_inum_eq(subvol_inum a, subvol_inum b)
157157 return a .subvol == b .subvol && a .inum == b .inum ;
158158}
159159
160+ static u32 bch2_vfs_inode_hash_fn (const void * data , u32 len , u32 seed )
161+ {
162+ const subvol_inum * inum = data ;
163+
164+ return jhash (& inum -> inum , sizeof (inum -> inum ), seed );
165+ }
166+
167+ static u32 bch2_vfs_inode_obj_hash_fn (const void * data , u32 len , u32 seed )
168+ {
169+ const struct bch_inode_info * inode = data ;
170+
171+ return bch2_vfs_inode_hash_fn (& inode -> ei_inum , sizeof (inode -> ei_inum ), seed );
172+ }
173+
160174static int bch2_vfs_inode_cmp_fn (struct rhashtable_compare_arg * arg ,
161175 const void * obj )
162176{
@@ -170,32 +184,93 @@ static const struct rhashtable_params bch2_vfs_inodes_params = {
170184 .head_offset = offsetof(struct bch_inode_info , hash ),
171185 .key_offset = offsetof(struct bch_inode_info , ei_inum ),
172186 .key_len = sizeof (subvol_inum ),
187+ .hashfn = bch2_vfs_inode_hash_fn ,
188+ .obj_hashfn = bch2_vfs_inode_obj_hash_fn ,
173189 .obj_cmpfn = bch2_vfs_inode_cmp_fn ,
174190 .automatic_shrinking = true,
175191};
176192
177- static struct bch_inode_info * __bch2_inode_hash_find (struct bch_fs * c , subvol_inum inum )
193+ int bch2_inode_or_descendents_is_open (struct btree_trans * trans , struct bpos p )
178194{
179- return rhashtable_lookup_fast (& c -> vfs_inodes_table , & inum , bch2_vfs_inodes_params );
180- }
195+ struct bch_fs * c = trans -> c ;
196+ struct rhashtable * ht = & c -> vfs_inodes_table ;
197+ subvol_inum inum = (subvol_inum ) { .inum = p .offset };
198+ DARRAY (u32 ) subvols ;
199+ int ret = 0 ;
181200
182- bool bch2_inode_is_open (struct bch_fs * c , struct bpos p )
183- {
184201 if (!test_bit (BCH_FS_started , & c -> flags ))
185202 return false;
186203
187- subvol_inum inum = {
188- .subvol = snapshot_t (c , p .snapshot )-> subvol ,
189- .inum = p .offset ,
190- };
204+ darray_init (& subvols );
205+ restart_from_top :
206+
207+ /*
208+ * Tweaked version of __rhashtable_lookup(); we need to get a list of
209+ * subvolumes in which the given inode number is open.
210+ *
211+ * For this to work, we don't include the subvolume ID in the key that
212+ * we hash - all inodes with the same inode number regardless of
213+ * subvolume will hash to the same slot.
214+ *
215+ * This will be less than ideal if the same file is ever open
216+ * simultaneously in many different snapshots:
217+ */
218+ rcu_read_lock ();
219+ struct rhash_lock_head __rcu * const * bkt ;
220+ struct rhash_head * he ;
221+ unsigned int hash ;
222+ struct bucket_table * tbl = rht_dereference_rcu (ht -> tbl , ht );
223+ restart :
224+ hash = rht_key_hashfn (ht , tbl , & inum , bch2_vfs_inodes_params );
225+ bkt = rht_bucket (tbl , hash );
226+ do {
227+ struct bch_inode_info * inode ;
228+
229+ rht_for_each_entry_rcu_from (inode , he , rht_ptr_rcu (bkt ), tbl , hash , hash ) {
230+ if (inode -> ei_inum .inum == inum .inum ) {
231+ ret = darray_push_gfp (& subvols , inode -> ei_inum .subvol ,
232+ GFP_NOWAIT |__GFP_NOWARN );
233+ if (ret ) {
234+ rcu_read_unlock ();
235+ ret = darray_make_room (& subvols , 1 );
236+ if (ret )
237+ goto err ;
238+ subvols .nr = 0 ;
239+ goto restart_from_top ;
240+ }
241+ }
242+ }
243+ /* An object might have been moved to a different hash chain,
244+ * while we walk along it - better check and retry.
245+ */
246+ } while (he != RHT_NULLS_MARKER (bkt ));
247+
248+ /* Ensure we see any new tables. */
249+ smp_rmb ();
250+
251+ tbl = rht_dereference_rcu (tbl -> future_tbl , ht );
252+ if (unlikely (tbl ))
253+ goto restart ;
254+ rcu_read_unlock ();
255+
256+ darray_for_each (subvols , i ) {
257+ u32 snap ;
258+ ret = bch2_subvolume_get_snapshot (trans , * i , & snap );
259+ if (ret )
260+ goto err ;
191261
192- /* snapshot tree interior node, can't safely delete while online (yet) */
193- if (!inum .subvol ) {
194- bch_warn_ratelimited (c , "%s(): snapshot %u has no subvol, unlinked but can't safely delete" , __func__ , p .snapshot );
195- return true;
262+ ret = bch2_snapshot_is_ancestor (c , snap , p .snapshot );
263+ if (ret )
264+ break ;
196265 }
266+ err :
267+ darray_exit (& subvols );
268+ return ret ;
269+ }
197270
198- return __bch2_inode_hash_find (c , inum ) != NULL ;
271+ static struct bch_inode_info * __bch2_inode_hash_find (struct bch_fs * c , subvol_inum inum )
272+ {
273+ return rhashtable_lookup_fast (& c -> vfs_inodes_table , & inum , bch2_vfs_inodes_params );
199274}
200275
201276static void __wait_on_freeing_inode (struct bch_fs * c ,
@@ -271,7 +346,8 @@ static struct bch_inode_info *bch2_inode_hash_insert(struct bch_fs *c,
271346
272347 set_bit (EI_INODE_HASHED , & inode -> ei_flags );
273348retry :
274- if (unlikely (rhashtable_lookup_insert_fast (& c -> vfs_inodes_table ,
349+ if (unlikely (rhashtable_lookup_insert_key (& c -> vfs_inodes_table ,
350+ & inode -> ei_inum ,
275351 & inode -> hash ,
276352 bch2_vfs_inodes_params ))) {
277353 old = bch2_inode_hash_find (c , trans , inode -> ei_inum );
0 commit comments