@@ -211,6 +211,124 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
211211 return hfs_brec_find (fd );
212212}
213213
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+ }
214332
215333/*
216334 * hfs_cat_delete()
@@ -271,6 +389,11 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, const struct qstr *str)
271389 dir -> i_size -- ;
272390 inode_set_mtime_to_ts (dir , inode_set_ctime_current (dir ));
273391 mark_inode_dirty (dir );
392+
393+ res = hfs_correct_next_unused_CNID (sb , cnid );
394+ if (res )
395+ goto out ;
396+
274397 res = 0 ;
275398out :
276399 hfs_find_exit (& fd );
0 commit comments