diff --git a/kmod/src/server.c b/kmod/src/server.c index 65b5d116..f4e09031 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -1299,12 +1299,10 @@ static int finalize_and_start_log_merge(struct super_block *sb, struct scoutfs_l * is nested inside holding commits so we recheck the persistent item * each time we commit to make sure it's still what we think. The * caller is still going to send the item to the client so we update the - * caller's each time we make progress. This is a best-effort attempt - * to clean up and it's valid to leave extents in data_freed we don't - * return errors to the caller. The client will continue the work later - * in get_log_trees or as the rid is reclaimed. + * caller's each time we make progress. If we hit an error applying the + * changes we make then we can't send the log_trees to the client. */ -static void try_drain_data_freed(struct super_block *sb, struct scoutfs_log_trees *lt) +static int try_drain_data_freed(struct super_block *sb, struct scoutfs_log_trees *lt) { DECLARE_SERVER_INFO(sb, server); struct scoutfs_super_block *super = DIRTY_SUPER_SB(sb); @@ -1313,6 +1311,7 @@ static void try_drain_data_freed(struct super_block *sb, struct scoutfs_log_tree struct scoutfs_log_trees drain; struct scoutfs_key key; COMMIT_HOLD(hold); + bool apply = false; int ret = 0; int err; @@ -1321,22 +1320,27 @@ static void try_drain_data_freed(struct super_block *sb, struct scoutfs_log_tree while (lt->data_freed.total_len != 0) { server_hold_commit(sb, &hold); mutex_lock(&server->logs_mutex); + apply = true; ret = find_log_trees_item(sb, &super->logs_root, false, rid, U64_MAX, &drain); - if (ret < 0) + if (ret < 0) { + ret = 0; break; + } /* careful to only keep draining the caller's specific open trans */ if (drain.nr != lt->nr || drain.get_trans_seq != lt->get_trans_seq || drain.commit_trans_seq != lt->commit_trans_seq || drain.flags != lt->flags) { - ret = -ENOENT; + ret = 0; break; } ret = scoutfs_btree_dirty(sb, &server->alloc, &server->wri, &super->logs_root, &key); - if (ret < 0) + if (ret < 0) { + ret = 0; break; + } /* moving can modify and return errors, always update caller and item */ mutex_lock(&server->alloc_mutex); @@ -1352,19 +1356,19 @@ static void try_drain_data_freed(struct super_block *sb, struct scoutfs_log_tree BUG_ON(err < 0); /* dirtying must guarantee success */ mutex_unlock(&server->logs_mutex); - ret = server_apply_commit(sb, &hold, ret); - if (ret < 0) { - ret = 0; /* don't try to abort, ignoring ret */ + apply = false; + + if (ret < 0) break; - } } - /* try to cleanly abort and write any partial dirty btree blocks, but ignore result */ - if (ret < 0) { + if (apply) { mutex_unlock(&server->logs_mutex); - server_apply_commit(sb, &hold, 0); + server_apply_commit(sb, &hold, ret); } + + return ret; } /* @@ -1572,9 +1576,9 @@ out: scoutfs_err(sb, "error %d getting log trees for rid %016llx: %s", ret, rid, err_str); - /* try to drain excessive data_freed with additional commits, if needed, ignoring err */ + /* try to drain excessive data_freed with additional commits, if needed */ if (ret == 0) - try_drain_data_freed(sb, <); + ret = try_drain_data_freed(sb, <); return scoutfs_net_response(sb, conn, cmd, id, ret, <, sizeof(lt)); }