+static int
+xfs_dir2_data_block_free(
+ xfs_da_args_t *args,
+ struct xfs_dir2_data_hdr *hdr,
+ struct xfs_dir2_free *free,
+ xfs_dir2_db_t fdb,
+ int findex,
+ struct xfs_buf *fbp,
+ int longest)
+{
+ struct xfs_trans *tp = args->trans;
+ int logfree = 0;
+
+ if (!hdr) {
+ /* One less used entry in the free table. */
+ be32_add_cpu(&free->hdr.nused, -1);
+ xfs_dir2_free_log_header(tp, fbp);
+
+ /*
+ * If this was the last entry in the table, we can trim the
+ * table size back. There might be other entries at the end
+ * referring to non-existent data blocks, get those too.
+ */
+ if (findex == be32_to_cpu(free->hdr.nvalid) - 1) {
+ int i; /* free entry index */
+
+ for (i = findex - 1; i >= 0; i--) {
+ if (free->bests[i] != cpu_to_be16(NULLDATAOFF))
+ break;
+ }
+ free->hdr.nvalid = cpu_to_be32(i + 1);
+ logfree = 0;
+ } else {
+ /* Not the last entry, just punch it out. */
+ free->bests[findex] = cpu_to_be16(NULLDATAOFF);
+ logfree = 1;
+ }
+ /*
+ * If there are no useful entries left in the block,
+ * get rid of the block if we can.
+ */
+ if (!free->hdr.nused) {
+ int error;
+
+ error = xfs_dir2_shrink_inode(args, fdb, fbp);
+ if (error == 0) {
+ fbp = NULL;
+ logfree = 0;
+ } else if (error != ENOSPC || args->total != 0)
+ return error;
+ /*
+ * It's possible to get ENOSPC if there is no
+ * space reservation. In this case some one
+ * else will eventually get rid of this block.
+ */
+ }
+ } else {
+ /*
+ * Data block is not empty, just set the free entry to the new
+ * value.
+ */
+ free->bests[findex] = cpu_to_be16(longest);
+ logfree = 1;
+ }
+
+ /* Log the free entry that changed, unless we got rid of it. */
+ if (logfree)
+ xfs_dir2_free_log_bests(tp, fbp, findex, findex);
+ return 0;
+}
+