+static void free_full_branch(struct inode *inode, int depth, void *p)
+{
+ struct super_block *sb = inode->i_sb;
+ struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+ struct ufs_inode_info *ufsi = UFS_I(inode);
+ struct ufs_buffer_head *ubh;
+ u64 tmp;
+ unsigned i;
+
+ tmp = ufs_data_ptr_to_cpu(sb, p);
+ if (!tmp)
+ return;
+ ubh = ubh_bread (sb, tmp, uspi->s_bsize);
+ if (!ubh) {
+ write_seqlock(&ufsi->meta_lock);
+ ufs_data_ptr_clear(uspi, p);
+ write_sequnlock(&ufsi->meta_lock);
+ return;
+ }
+
+ if (--depth) {
+ for (i = 0 ; i < uspi->s_apb ; i++) {
+ void *ind = ubh_get_data_ptr(uspi, ubh, i);
+ free_full_branch(inode, depth, ind);
+ ubh_mark_buffer_dirty(ubh);
+ }
+ } else {
+ struct to_free ctx = {.inode = inode};
+
+ for (i = 0; i < uspi->s_apb; i++) {
+ void *ind = ubh_get_data_ptr(uspi, ubh, i);
+ tmp = ufs_data_ptr_to_cpu(sb, ind);
+ if (!tmp)
+ continue;
+
+ write_seqlock(&UFS_I(inode)->meta_lock);
+ ufs_data_ptr_clear(uspi, ind);
+ write_sequnlock(&UFS_I(inode)->meta_lock);
+ ubh_mark_buffer_dirty(ubh);
+ free_data(&ctx, tmp, uspi->s_fpb);
+ mark_inode_dirty(inode);
+ }
+ free_data(&ctx, 0, 0);
+ }
+ tmp = ufs_data_ptr_to_cpu(sb, p);
+ write_seqlock(&ufsi->meta_lock);
+ ufs_data_ptr_clear(uspi, p);
+ write_sequnlock(&ufsi->meta_lock);
+
+ ubh_bforget(ubh);
+ ufs_free_blocks(inode, tmp, uspi->s_fpb);
+ mark_inode_dirty(inode);
+}
+