diff options
-rw-r--r-- | block/nbd-client.c | 2 | ||||
-rw-r--r-- | linux-user/main.c | 3 | ||||
-rw-r--r-- | linux-user/signal.c | 55 | ||||
-rw-r--r-- | linux-user/syscall.c | 36 | ||||
-rw-r--r-- | linux-user/xtensa/target_structs.h | 37 | ||||
-rw-r--r-- | nbd/client.c | 30 | ||||
-rw-r--r-- | nbd/server.c | 8 | ||||
-rw-r--r-- | nbd/trace-events | 6 |
8 files changed, 120 insertions, 57 deletions
diff --git a/block/nbd-client.c b/block/nbd-client.c index e64e346d69..e7caf49fbb 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -239,7 +239,7 @@ static int nbd_parse_blockstatus_payload(NBDClientSession *client, { uint32_t context_id; - if (chunk->length != sizeof(context_id) + sizeof(extent)) { + if (chunk->length != sizeof(context_id) + sizeof(*extent)) { error_setg(errp, "Protocol error: invalid payload for " "NBD_REPLY_TYPE_BLOCK_STATUS"); return -EINVAL; diff --git a/linux-user/main.c b/linux-user/main.c index ba09b7d0c8..8907a84114 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4006,6 +4006,9 @@ void cpu_loop(CPUXtensaState *env) break; case -TARGET_ERESTARTSYS: + env->pc -= 3; + break; + case -TARGET_QEMU_ESIGRETURN: break; } diff --git a/linux-user/signal.c b/linux-user/signal.c index 2ea3e0321f..33d5ced30c 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -7094,52 +7094,45 @@ static abi_ulong get_sigframe(struct target_sigaction *sa, static int flush_window_regs(CPUXtensaState *env) { - const uint32_t nareg_mask = env->config->nareg - 1; uint32_t wb = env->sregs[WINDOW_BASE]; - uint32_t ws = (xtensa_replicate_windowstart(env) >> (wb + 1)) & - ((1 << env->config->nareg / 4) - 1); - uint32_t d = ctz32(ws) + 1; - uint32_t sp; - abi_long ret = 0; - - wb += d; - ws >>= d; + uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1); + unsigned d = ctz32(ws) + 1; + unsigned i; + int ret = 0; - xtensa_sync_phys_from_window(env); - sp = env->phys_regs[(wb * 4 + 1) & nareg_mask]; + for (i = d; i < env->config->nareg / 4; i += d) { + uint32_t ssp, osp; + unsigned j; - while (ws && ret == 0) { - int d; - int i; - int idx; + ws >>= d; + xtensa_rotate_window(env, d); if (ws & 0x1) { - ws >>= 1; + ssp = env->regs[5]; d = 1; } else if (ws & 0x2) { - ws >>= 2; + ssp = env->regs[9]; + ret |= get_user_ual(osp, env->regs[1] - 12); + osp -= 32; d = 2; - for (i = 0; i < 4; ++i) { - idx = (wb * 4 + 4 + i) & nareg_mask; - ret |= put_user_ual(env->phys_regs[idx], sp + (i - 12) * 4); - } } else if (ws & 0x4) { - ws >>= 3; + ssp = env->regs[13]; + ret |= get_user_ual(osp, env->regs[1] - 12); + osp -= 48; d = 3; - for (i = 0; i < 8; ++i) { - idx = (wb * 4 + 4 + i) & nareg_mask; - ret |= put_user_ual(env->phys_regs[idx], sp + (i - 16) * 4); - } } else { g_assert_not_reached(); } - sp = env->phys_regs[((wb + d) * 4 + 1) & nareg_mask]; - for (i = 0; i < 4; ++i) { - idx = (wb * 4 + i) & nareg_mask; - ret |= put_user_ual(env->phys_regs[idx], sp + (i - 4) * 4); + + for (j = 0; j < 4; ++j) { + ret |= put_user_ual(env->regs[j], ssp - 16 + j * 4); + } + for (j = 4; j < d * 4; ++j) { + ret |= put_user_ual(env->regs[j], osp - 16 + j * 4); } - wb += d; } + xtensa_rotate_window(env, d); + g_assert(env->sregs[WINDOW_BASE] == wb); return ret == 0; } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 889abbda1e..5ef5176135 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6346,6 +6346,10 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, ts = g_new0(TaskState, 1); init_task_state(ts); + + /* Grab a mutex so that thread setup appears atomic. */ + pthread_mutex_lock(&clone_lock); + /* we create a new CPU instance. */ new_env = cpu_copy(env); /* Init regs that differ from the parent. */ @@ -6364,9 +6368,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, cpu_set_tls (new_env, newtls); } - /* Grab a mutex so that thread setup appears atomic. */ - pthread_mutex_lock(&clone_lock); - memset(&info, 0, sizeof(info)); pthread_mutex_init(&info.mutex, NULL); pthread_mutex_lock(&info.mutex); @@ -11508,7 +11509,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_fadvise64_64 case TARGET_NR_fadvise64_64: -#if defined(TARGET_PPC) +#if defined(TARGET_PPC) || defined(TARGET_XTENSA) /* 6 args: fd, advice, offset (high, low), len (high, low) */ ret = arg2; arg2 = arg3; @@ -11877,13 +11878,25 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented_nowarn; #endif +#ifdef TARGET_NR_clock_settime + case TARGET_NR_clock_settime: + { + struct timespec ts; + + ret = target_to_host_timespec(&ts, arg2); + if (!is_error(ret)) { + ret = get_errno(clock_settime(arg1, &ts)); + } + break; + } +#endif #ifdef TARGET_NR_clock_gettime case TARGET_NR_clock_gettime: { struct timespec ts; ret = get_errno(clock_gettime(arg1, &ts)); if (!is_error(ret)) { - host_to_target_timespec(arg2, &ts); + ret = host_to_target_timespec(arg2, &ts); } break; } @@ -12091,15 +12104,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct mq_attr posix_mq_attr_in, posix_mq_attr_out; ret = 0; - if (arg3 != 0) { - ret = mq_getattr(arg1, &posix_mq_attr_out); - copy_to_user_mq_attr(arg3, &posix_mq_attr_out); - } if (arg2 != 0) { copy_from_user_mq_attr(&posix_mq_attr_in, arg2); - ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out); + ret = get_errno(mq_setattr(arg1, &posix_mq_attr_in, + &posix_mq_attr_out)); + } else if (arg3 != 0) { + ret = get_errno(mq_getattr(arg1, &posix_mq_attr_out)); + } + if (ret == 0 && arg3 != 0) { + copy_to_user_mq_attr(arg3, &posix_mq_attr_out); } - } break; #endif diff --git a/linux-user/xtensa/target_structs.h b/linux-user/xtensa/target_structs.h index 020e20e242..1b3d9ca314 100644 --- a/linux-user/xtensa/target_structs.h +++ b/linux-user/xtensa/target_structs.h @@ -8,21 +8,44 @@ struct target_ipc_perm { abi_uint cuid; /* Creator's user ID. */ abi_uint cgid; /* Creator's group ID. */ abi_uint mode; /* Read/write permission. */ - abi_ushort __seq; /* Sequence number. */ + abi_ulong __seq; /* Sequence number. */ + abi_ulong __unused1; + abi_ulong __unused2; +}; + +struct target_semid64_ds { + struct target_ipc_perm sem_perm; +#ifdef TARGET_WORDS_BIGENDIAN + abi_ulong __unused1; + abi_ulong sem_otime; + abi_ulong __unused2; + abi_ulong sem_ctime; +#else + abi_ulong sem_otime; + abi_ulong __unused1; + abi_ulong sem_ctime; + abi_ulong __unused2; +#endif + abi_ulong sem_nsems; + abi_ulong __unused3; + abi_ulong __unused4; }; +#define TARGET_SEMID64_DS struct target_shmid_ds { struct target_ipc_perm shm_perm; /* operation permission struct */ - abi_int shm_segsz; /* size of segment in bytes */ + abi_long shm_segsz; /* size of segment in bytes */ abi_long shm_atime; /* time of last shmat() */ + abi_ulong __unused1; abi_long shm_dtime; /* time of last shmdt() */ - abi_long shm_ctime; /* time of last change by shmctl() */ - abi_ushort shm_cpid; /* pid of creator */ - abi_ushort shm_lpid; /* pid of last shmop */ - abi_ushort shm_nattch; /* number of current attaches */ - abi_ushort shm_unused; /* compatibility */ abi_ulong __unused2; + abi_long shm_ctime; /* time of last change by shmctl() */ abi_ulong __unused3; + abi_uint shm_cpid; /* pid of creator */ + abi_uint shm_lpid; /* pid of last shmop */ + abi_ulong shm_nattch; /* number of current attaches */ + abi_ulong __unused4; + abi_ulong __unused5; }; #endif diff --git a/nbd/client.c b/nbd/client.c index 9b9b7f0ea2..b9e175d1c2 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -599,8 +599,8 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc, * Set one meta context. Simple means that reply must contain zero (not * negotiated) or one (negotiated) contexts. More contexts would be considered * as a protocol error. It's also implied that meta-data query equals queried - * context name, so, if server replies with something different then @context, - * it considered as error too. + * context name, so, if server replies with something different than @context, + * it is considered an error too. * return 1 for successful negotiation, context_id is set * 0 if operation is unsupported, * -1 with errp set for any other error @@ -623,6 +623,7 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, char *data = g_malloc(data_len); char *p = data; + trace_nbd_opt_meta_request(context, export); stl_be_p(p, export_len); memcpy(p += sizeof(export_len), export, export_len); stl_be_p(p += export_len, 1); @@ -649,29 +650,38 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, if (reply.type == NBD_REP_META_CONTEXT) { char *name; - size_t len; + + if (reply.length != sizeof(received_id) + context_len) { + error_setg(errp, "Failed to negotiate meta context '%s', server " + "answered with unexpected length %" PRIu32, context, + reply.length); + nbd_send_opt_abort(ioc); + return -1; + } if (nbd_read(ioc, &received_id, sizeof(received_id), errp) < 0) { return -1; } be32_to_cpus(&received_id); - len = reply.length - sizeof(received_id); - name = g_malloc(len + 1); - if (nbd_read(ioc, name, len, errp) < 0) { + reply.length -= sizeof(received_id); + name = g_malloc(reply.length + 1); + if (nbd_read(ioc, name, reply.length, errp) < 0) { g_free(name); return -1; } - name[len] = '\0'; + name[reply.length] = '\0'; if (strcmp(context, name)) { error_setg(errp, "Failed to negotiate meta context '%s', server " "answered with different context '%s'", context, name); g_free(name); + nbd_send_opt_abort(ioc); return -1; } g_free(name); + trace_nbd_opt_meta_reply(context, received_id); received = true; /* receive NBD_REP_ACK */ @@ -690,6 +700,12 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, if (reply.type != NBD_REP_ACK) { error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x", reply.type, NBD_REP_ACK); + nbd_send_opt_abort(ioc); + return -1; + } + if (reply.length) { + error_setg(errp, "Unexpected length to ACK response"); + nbd_send_opt_abort(ioc); return -1; } diff --git a/nbd/server.c b/nbd/server.c index cea158913b..9e1f227178 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -726,6 +726,7 @@ static int nbd_negotiate_send_meta_context(NBDClient *client, context_id = 0; } + trace_nbd_negotiate_meta_query_reply(context, context_id); set_be_option_rep(&opt.h, client->opt, NBD_REP_META_CONTEXT, sizeof(opt) - sizeof(opt.h) + iov[1].iov_len); stl_be_p(&opt.context_id, context_id); @@ -752,10 +753,12 @@ static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, if (client->opt == NBD_OPT_LIST_META_CONTEXT) { meta->base_allocation = true; } + trace_nbd_negotiate_meta_query_parse("base:"); return 1; } if (len != alen) { + trace_nbd_negotiate_meta_query_skip("not base:allocation"); return nbd_opt_skip(client, len, errp); } @@ -768,6 +771,7 @@ static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, meta->base_allocation = true; } + trace_nbd_negotiate_meta_query_parse("base:allocation"); return 1; } @@ -800,6 +804,7 @@ static int nbd_negotiate_meta_query(NBDClient *client, /* The only supported namespace for now is 'base'. So query should start * with 'base:'. Otherwise, we can ignore it and skip the remainder. */ if (len < baselen) { + trace_nbd_negotiate_meta_query_skip("length too short"); return nbd_opt_skip(client, len, errp); } @@ -809,6 +814,7 @@ static int nbd_negotiate_meta_query(NBDClient *client, return ret; } if (strncmp(query, "base:", baselen) != 0) { + trace_nbd_negotiate_meta_query_skip("not for base: namespace"); return nbd_opt_skip(client, len, errp); } @@ -858,6 +864,8 @@ static int nbd_negotiate_meta_queries(NBDClient *client, return ret; } cpu_to_be32s(&nb_queries); + trace_nbd_negotiate_meta_context(nbd_opt_lookup(client->opt), + meta->export_name, nb_queries); if (client->opt == NBD_OPT_LIST_META_CONTEXT && !nb_queries) { /* enable all known contexts */ diff --git a/nbd/trace-events b/nbd/trace-events index 0d03edc967..dee081e775 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -10,6 +10,8 @@ nbd_receive_query_exports_start(const char *wantname) "Querying export list for nbd_receive_query_exports_success(const char *wantname) "Found desired export name '%s'" nbd_receive_starttls_new_client(void) "Setting up TLS" nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake" +nbd_opt_meta_request(const char *context, const char *export) "Requesting to set meta context %s for export %s" +nbd_opt_meta_reply(const char *context, uint32_t id) "Received mapping of context %s to id %" PRIu32 nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s" nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64 nbd_receive_negotiate_server_flags(uint32_t globalflags) "Global flags are 0x%" PRIx32 @@ -44,6 +46,10 @@ nbd_negotiate_handle_info_request(int request, const char *name) "Client request nbd_negotiate_handle_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "advertising minimum 0x%" PRIx32 ", preferred 0x%" PRIx32 ", maximum 0x%" PRIx32 nbd_negotiate_handle_starttls(void) "Setting up TLS" nbd_negotiate_handle_starttls_handshake(void) "Starting TLS handshake" +nbd_negotiate_meta_context(const char *optname, const char *export, uint32_t queries) "Client requested %s for export %s, with %" PRIu32 " queries" +nbd_negotiate_meta_query_skip(const char *reason) "Skipping meta query: %s" +nbd_negotiate_meta_query_parse(const char *query) "Parsed meta query '%s'" +nbd_negotiate_meta_query_reply(const char *context, uint32_t id) "Replying with meta context '%s' id %" PRIu32 nbd_negotiate_options_flags(uint32_t flags) "Received client flags 0x%" PRIx32 nbd_negotiate_options_check_magic(uint64_t magic) "Checking opts magic 0x%" PRIx64 nbd_negotiate_options_check_option(uint32_t option, const char *name) "Checking option %" PRIu32 " (%s)" |