{ "rotational", FALSE, PARAM_BOOL, &(s.flags), F_ROTATIONAL },
{ "temporary", FALSE, PARAM_BOOL, &(s.flags), F_TEMPORARY },
{ "trim", FALSE, PARAM_BOOL, &(s.flags), F_TRIM },
+ { "datalog", FALSE, PARAM_BOOL, &(s.flags), F_DATALOG },
{ "listenaddr", FALSE, PARAM_STRING, &(s.listenaddr), 0 },
{ "maxconnections", FALSE, PARAM_INT, &(s.max_connections), 0 },
{ "force_tls", FALSE, PARAM_BOOL, &(s.flags), F_FORCEDTLS },
g_key_file_free(cfile);
return NULL;
}
+ /* We can't mix datalog and splice. */
+ if ((s.flags & F_DATALOG) && (s.flags & F_SPLICE)) {
+ g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_INVALID_SPLICE,
+ "Cannot mix datalog with splice for an export in group %s",
+ groups[i]);
+ g_array_free(retval, TRUE);
+ g_key_file_free(cfile);
+ return NULL;
+ }
/* Don't need to free this, it's not our string */
virtstyle=NULL;
/* Don't append values for the [generic] group */
}
/**
+ * Setup the transaction log
+ *
+ * The function does all things required for the transaction log:
+ * - Create a new log file.
+ * - Report if a log file already exists.
+ * - If needed add a header to the log.
+ *
+ * If something goes wrong, logging is disabled.
+ *
+ * @param client the CLIENT structure with .server and .net members set
+ * up correctly
+ */
+static void setup_transactionlog(CLIENT *client) {
+
+ if((client->transactionlogfd =
+ open(client->server->transactionlog,
+ O_WRONLY | O_CREAT,
+ S_IRUSR | S_IWUSR)) ==
+ -1) {
+ msg(LOG_INFO, "Could not open transactionlog %s, moving on without it",
+ client->server->transactionlog);
+ }
+ if (client->server->flags & F_DATALOG) {
+ struct nbd_request req;
+ int ret;
+
+ req.magic = htonl(NBD_TRACELOG_MAGIC);
+ req.type = htonl(NBD_TRACELOG_SET_DATALOG);
+ memset(req.handle, 0, sizeof(req.handle));
+ req.from = htonll(NBD_TRACELOG_FROM_MAGIC);
+ req.len = htonl(TRUE);
+
+ ret = writeit(client->transactionlogfd, &req, sizeof(struct nbd_request));
+ if (ret < 0) {
+ msg(LOG_INFO, "Could not write to transactionlog %s, moving on without it",
+ client->server->transactionlog);
+ close(client->transactionlogfd);
+ client->transactionlogfd = -1;
+ }
+ }
+}
+
+/**
* Commit to exporting the chosen export
*
* When a client sends NBD_OPT_EXPORT_NAME or NBD_OPT_GO, we need to do
}
/* Set up the transactionlog, if we need one */
- if (client->server->transactionlog && (client->transactionlogfd == -1)) {
- if((client->transactionlogfd =
- open(client->server->transactionlog,
- O_WRONLY | O_CREAT,
- S_IRUSR | S_IWUSR)) ==
- -1) {
- msg(LOG_INFO, "Could not open transactionlog %s, moving on without it",
- client->server->transactionlog);
- }
- }
+ if (client->server->transactionlog && (client->transactionlogfd == -1))
+ setup_transactionlog(client);
/* Run any pre scripts that we may need */
if (do_run(client->server->prerun, client->exportname)) {
else
#endif
socket_read(client, pkg->data, req->len);
+
+ if ((client->server->flags & F_DATALOG) &&
+ !(client->server->flags & F_SPLICE)) {
+ writeit(client->transactionlogfd, pkg->data, req->len);
+ }
}
if(req->type == NBD_CMD_DISC) {
finalize_client(client);
#include <sys/time.h>
#include <sys/types.h>
#include <stdint.h>
+#include <stdbool.h>
#include <unistd.h>
#include "config.h"
/* We don't want to do syslog output in this program */
#include "nbd.h"
#include "nbd-helper.h"
+#define BUFSIZE 131072
+static char tmpbuf[BUFSIZE];
+
+static bool g_with_datalog = false;
+
static inline void doread(int f, void *buf, size_t len) {
ssize_t res;
(command & NBD_CMD_FLAG_FUA)?"FUA":"NONE",
(long long unsigned int) offset,
len);
+ if (((command & NBD_CMD_MASK_COMMAND) == NBD_CMD_WRITE) &&
+ g_with_datalog) {
+ while (len > 0) {
+ uint32_t tmplen = len;
+
+ if (tmplen > BUFSIZE)
+ tmplen = BUFSIZE;
+ doread(readfd, tmpbuf, tmplen);
+ len -= tmplen;
+ }
+ }
break;
case NBD_REPLY_MAGIC:
error);
break;
+ case NBD_TRACELOG_MAGIC:
+ doread(readfd, sizeof(magic)+(char *)(&req), sizeof(struct nbd_request)-sizeof(magic));
+ handle = ntohll(*((long long int *)(req.handle)));
+ offset = ntohll(req.from);
+ len = ntohl(req.len);
+ command = ntohl(req.type);
+
+ ctext = gettracelogname(command);
+
+ printf("TRACE_OPTION C=0x%08x (%23s) O=%016llx L=%08x\n",
+ command,
+ ctext,
+ (long long unsigned int) offset,
+ len);
+ if (offset == NBD_TRACELOG_FROM_MAGIC) {
+
+ switch (command) {
+ case NBD_TRACELOG_SET_DATALOG:
+ g_with_datalog = !!len;
+ printf("TRACE_OPTION DATALOG set to %d.\n", (int)g_with_datalog);
+ break;
+ default:
+ printf("TRACE_OPTION ? Unknown type\n");
+ }
+ } else {
+ printf("TRACE_OPTION ? Unknown FROM_MAGIC\n");
+ }
+ break;
+
default:
printf("? Unknown transaction type %08x\n",magic);
break;