summaryrefslogtreecommitdiff
path: root/lib9p/tests/test_server/fs_flush.c
blob: 63a52affd449148c5458c652d47603f05604dd25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* lib9p/tests/test_server/fs_flush.c - flush-* API endpoints
 *
 * Copyright (C) 2024-2025  Luke T. Shumaker <lukeshu@lukeshu.com>
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#include <libmisc/alloc.h>

#define IMPLEMENTATION_FOR_LIB9P_SRV_H YES /* for ctx->flush_ch */
#include "fs_flush.h"

LO_IMPLEMENTATION_C(lib9p_srv_file, struct flush_file, flush_file, static);

struct flush_fio {
	struct flush_file *parent;
};
LO_IMPLEMENTATION_H(lib9p_srv_fio, struct flush_fio, flush_fio);
LO_IMPLEMENTATION_C(lib9p_srv_fio, struct flush_fio, flush_fio, static);

/* srv_file *******************************************************************/

static void flush_file_free(struct flush_file *self) {
	assert(self);
}
static struct lib9p_qid flush_file_qid(struct flush_file *self) {
	assert(self);
	return (struct lib9p_qid){
		.type = LIB9P_QT_FILE,
		.vers = 1,
		.path = self->pathnum,
	};
}

static lib9p_srv_stat_or_error flush_file_stat(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
	assert(self);
	assert(ctx);
	return ERROR_NEW_VAL(lib9p_srv_stat, ((struct lib9p_srv_stat){
		.qid                 = flush_file_qid(self),
		.mode                = 0444,
		.atime_sec           = UTIL9P_ATIME,
		.mtime_sec           = UTIL9P_MTIME,
		.size                = 6,
		.name                = lib9p_str(self->name),
		.owner_uid           = { .name = lib9p_str("root"), .num = 0 },
		.owner_gid           = { .name = lib9p_str("root"), .num = 0 },
		.last_modifier_uid   = { .name = lib9p_str("root"), .num = 0 },
		.extension           = lib9p_str(NULL),
	}));
}
static error flush_file_wstat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
	assert(self);
	assert(ctx);
	return error_new(E_POSIX_EROFS, "cannot wstat API file");
}
static error flush_file_remove(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
	assert(self);
	assert(ctx);
	return error_new(E_POSIX_EROFS, "cannot remove API file");
}

LIB9P_SRV_NOTDIR(struct flush_file, flush_file);

static lib9p_srv_fio_or_error flush_file_fopen(struct flush_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
	assert(self);
	assert(ctx);

	struct flush_fio *ret = heap_alloc(1, struct flush_fio);
	ret->parent = self;

	return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
}

/* srv_fio ********************************************************************/

static void flush_fio_iofree(struct flush_fio *self) {
	assert(self);
	free(self);
}

static struct lib9p_qid flush_fio_qid(struct flush_fio *self) {
	assert(self);
	return flush_file_qid(self->parent);
}

static uint32_t flush_fio_iounit(struct flush_fio *self) {
	assert(self);
	return 0;
}

static uint32_t_or_error flush_fio_pwrite(struct flush_fio *LM_UNUSED(self),
                                 struct lib9p_srv_ctx *LM_UNUSED(ctx),
                                 void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count),
                                 uint64_t LM_UNUSED(offset)) {
	assert_notreached("not writable");
}

static iovec_or_error flush_fio_pread(struct flush_fio *self, struct lib9p_srv_ctx *ctx,
                            uint32_t byte_count, uint64_t LM_UNUSED(byte_offset)) {
	assert(self);
	assert(ctx);

	/* Wait for first Tflush */
	while (!lib9p_srv_flush_requested(ctx))
		cr_yield();

	/* Wait for the specified number of Tflush (may be higher *or*
	 * lower than 1; lower would mean that the first Tflush needs
	 * to be flushed itself).  */
	while (cr_chan_num_waiters(&ctx->flush_ch) != self->parent->flush_cnt)
		cr_yield();

	/* Yield one more time, just because.  */
	cr_yield();

	/* Return */
	switch (self->parent->flush_behavior) {
	case FLUSH_READ:
		return ERROR_NEW_VAL(iovec, ((struct iovec){
			.iov_base = "Sloth\n",
			.iov_len = 6 < byte_count ? 6 : byte_count,
		}));
	case FLUSH_ERROR:
		return ERROR_NEW_ERR(iovec, error_new(E_POSIX_EAGAIN, "request canceled by flush"));
	case FLUSH_SILENT:
		return ERROR_NEW_ERR(iovec, error_new(E_POSIX_ECANCELED, "request canceled by flush"));
	default:
		assert_notreached("invalid flush_behavior");
	}
}