@@ -211,6 +211,124 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
211
211
return hfs_brec_find (fd );
212
212
}
213
213
214
+ static inline
215
+ void hfs_set_next_unused_CNID (struct super_block * sb ,
216
+ u32 deleted_cnid , u32 found_cnid )
217
+ {
218
+ if (found_cnid < HFS_FIRSTUSER_CNID ) {
219
+ atomic64_cmpxchg (& HFS_SB (sb )-> next_id ,
220
+ deleted_cnid + 1 , HFS_FIRSTUSER_CNID );
221
+ } else {
222
+ atomic64_cmpxchg (& HFS_SB (sb )-> next_id ,
223
+ deleted_cnid + 1 , found_cnid + 1 );
224
+ }
225
+ }
226
+
227
+ /*
228
+ * hfs_correct_next_unused_CNID()
229
+ *
230
+ * Correct the next unused CNID of Catalog Tree.
231
+ */
232
+ static
233
+ int hfs_correct_next_unused_CNID (struct super_block * sb , u32 cnid )
234
+ {
235
+ struct hfs_btree * cat_tree ;
236
+ struct hfs_bnode * node ;
237
+ s64 leaf_head ;
238
+ s64 leaf_tail ;
239
+ s64 node_id ;
240
+
241
+ hfs_dbg (CAT_MOD , "correct next unused CNID: cnid %u, next_id %lld\n" ,
242
+ cnid , atomic64_read (& HFS_SB (sb )-> next_id ));
243
+
244
+ if ((cnid + 1 ) < atomic64_read (& HFS_SB (sb )-> next_id )) {
245
+ /* next ID should be unchanged */
246
+ return 0 ;
247
+ }
248
+
249
+ cat_tree = HFS_SB (sb )-> cat_tree ;
250
+ leaf_head = cat_tree -> leaf_head ;
251
+ leaf_tail = cat_tree -> leaf_tail ;
252
+
253
+ if (leaf_head > leaf_tail ) {
254
+ pr_err ("node is corrupted: leaf_head %lld, leaf_tail %lld\n" ,
255
+ leaf_head , leaf_tail );
256
+ return - ERANGE ;
257
+ }
258
+
259
+ node = hfs_bnode_find (cat_tree , leaf_tail );
260
+ if (IS_ERR (node )) {
261
+ pr_err ("fail to find leaf node: node ID %lld\n" ,
262
+ leaf_tail );
263
+ return - ENOENT ;
264
+ }
265
+
266
+ node_id = leaf_tail ;
267
+
268
+ do {
269
+ int i ;
270
+
271
+ if (node_id != leaf_tail ) {
272
+ node = hfs_bnode_find (cat_tree , node_id );
273
+ if (IS_ERR (node ))
274
+ return - ENOENT ;
275
+ }
276
+
277
+ hfs_dbg (CAT_MOD , "node_id %lld, leaf_tail %lld, leaf_head %lld\n" ,
278
+ node_id , leaf_tail , leaf_head );
279
+
280
+ hfs_bnode_dump (node );
281
+
282
+ for (i = node -> num_recs - 1 ; i >= 0 ; i -- ) {
283
+ hfs_cat_rec rec ;
284
+ u16 off , len , keylen ;
285
+ int entryoffset ;
286
+ int entrylength ;
287
+ u32 found_cnid ;
288
+
289
+ len = hfs_brec_lenoff (node , i , & off );
290
+ keylen = hfs_brec_keylen (node , i );
291
+ if (keylen == 0 ) {
292
+ pr_err ("fail to get the keylen: "
293
+ "node_id %lld, record index %d\n" ,
294
+ node_id , i );
295
+ return - EINVAL ;
296
+ }
297
+
298
+ entryoffset = off + keylen ;
299
+ entrylength = len - keylen ;
300
+
301
+ if (entrylength > sizeof (rec )) {
302
+ pr_err ("unexpected record length: "
303
+ "entrylength %d\n" ,
304
+ entrylength );
305
+ return - EINVAL ;
306
+ }
307
+
308
+ hfs_bnode_read (node , & rec , entryoffset , entrylength );
309
+
310
+ if (rec .type == HFS_CDR_DIR ) {
311
+ found_cnid = be32_to_cpu (rec .dir .DirID );
312
+ hfs_dbg (CAT_MOD , "found_cnid %u\n" , found_cnid );
313
+ hfs_set_next_unused_CNID (sb , cnid , found_cnid );
314
+ hfs_bnode_put (node );
315
+ return 0 ;
316
+ } else if (rec .type == HFS_CDR_FIL ) {
317
+ found_cnid = be32_to_cpu (rec .file .FlNum );
318
+ hfs_dbg (CAT_MOD , "found_cnid %u\n" , found_cnid );
319
+ hfs_set_next_unused_CNID (sb , cnid , found_cnid );
320
+ hfs_bnode_put (node );
321
+ return 0 ;
322
+ }
323
+ }
324
+
325
+ hfs_bnode_put (node );
326
+
327
+ node_id = node -> prev ;
328
+ } while (node_id >= leaf_head );
329
+
330
+ return - ENOENT ;
331
+ }
214
332
215
333
/*
216
334
* hfs_cat_delete()
@@ -271,6 +389,11 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, const struct qstr *str)
271
389
dir -> i_size -- ;
272
390
inode_set_mtime_to_ts (dir , inode_set_ctime_current (dir ));
273
391
mark_inode_dirty (dir );
392
+
393
+ res = hfs_correct_next_unused_CNID (sb , cnid );
394
+ if (res )
395
+ goto out ;
396
+
274
397
res = 0 ;
275
398
out :
276
399
hfs_find_exit (& fd );
0 commit comments