improved cmsg handling - improved shm memory code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3600 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
745cacc7b7
commit
5a4a898d81
@ -669,12 +669,22 @@ static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ??? Should this also swap msgh->name? */
|
/* ??? Should this also swap msgh->name? */
|
||||||
static inline void target_to_host_cmsg(struct msghdr *msgh,
|
static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
|
||||||
struct target_msghdr *target_msgh)
|
struct target_msghdr *target_msgh)
|
||||||
{
|
{
|
||||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
|
||||||
struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh);
|
abi_long msg_controllen;
|
||||||
|
abi_ulong target_cmsg_addr;
|
||||||
|
struct target_cmsghdr *target_cmsg;
|
||||||
socklen_t space = 0;
|
socklen_t space = 0;
|
||||||
|
|
||||||
|
msg_controllen = tswapl(target_msgh->msg_controllen);
|
||||||
|
if (msg_controllen < sizeof (struct target_cmsghdr))
|
||||||
|
goto the_end;
|
||||||
|
target_cmsg_addr = tswapl(target_msgh->msg_control);
|
||||||
|
target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
|
||||||
|
if (!target_cmsg)
|
||||||
|
return -TARGET_EFAULT;
|
||||||
|
|
||||||
while (cmsg && target_cmsg) {
|
while (cmsg && target_cmsg) {
|
||||||
void *data = CMSG_DATA(cmsg);
|
void *data = CMSG_DATA(cmsg);
|
||||||
@ -709,18 +719,30 @@ static inline void target_to_host_cmsg(struct msghdr *msgh,
|
|||||||
cmsg = CMSG_NXTHDR(msgh, cmsg);
|
cmsg = CMSG_NXTHDR(msgh, cmsg);
|
||||||
target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
|
target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
|
||||||
}
|
}
|
||||||
|
unlock_user(target_cmsg, target_cmsg_addr, 0);
|
||||||
|
the_end:
|
||||||
msgh->msg_controllen = space;
|
msgh->msg_controllen = space;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ??? Should this also swap msgh->name? */
|
/* ??? Should this also swap msgh->name? */
|
||||||
static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
|
static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
|
||||||
struct msghdr *msgh)
|
struct msghdr *msgh)
|
||||||
{
|
{
|
||||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
|
||||||
struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh);
|
abi_long msg_controllen;
|
||||||
|
abi_ulong target_cmsg_addr;
|
||||||
|
struct target_cmsghdr *target_cmsg;
|
||||||
socklen_t space = 0;
|
socklen_t space = 0;
|
||||||
|
|
||||||
|
msg_controllen = tswapl(target_msgh->msg_controllen);
|
||||||
|
if (msg_controllen < sizeof (struct target_cmsghdr))
|
||||||
|
goto the_end;
|
||||||
|
target_cmsg_addr = tswapl(target_msgh->msg_control);
|
||||||
|
target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
|
||||||
|
if (!target_cmsg)
|
||||||
|
return -TARGET_EFAULT;
|
||||||
|
|
||||||
while (cmsg && target_cmsg) {
|
while (cmsg && target_cmsg) {
|
||||||
void *data = CMSG_DATA(cmsg);
|
void *data = CMSG_DATA(cmsg);
|
||||||
void *target_data = TARGET_CMSG_DATA(target_cmsg);
|
void *target_data = TARGET_CMSG_DATA(target_cmsg);
|
||||||
@ -728,7 +750,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
|
|||||||
int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
|
int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
|
||||||
|
|
||||||
space += TARGET_CMSG_SPACE(len);
|
space += TARGET_CMSG_SPACE(len);
|
||||||
if (space > tswapl(target_msgh->msg_controllen)) {
|
if (space > msg_controllen) {
|
||||||
space -= TARGET_CMSG_SPACE(len);
|
space -= TARGET_CMSG_SPACE(len);
|
||||||
gemu_log("Target cmsg overflow\n");
|
gemu_log("Target cmsg overflow\n");
|
||||||
break;
|
break;
|
||||||
@ -753,8 +775,10 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
|
|||||||
cmsg = CMSG_NXTHDR(msgh, cmsg);
|
cmsg = CMSG_NXTHDR(msgh, cmsg);
|
||||||
target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
|
target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
|
||||||
}
|
}
|
||||||
|
unlock_user(target_cmsg, target_cmsg_addr, space);
|
||||||
msgh->msg_controllen = tswapl(space);
|
the_end:
|
||||||
|
target_msgh->msg_controllen = tswapl(space);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* do_setsockopt() Must return target values and target errnos. */
|
/* do_setsockopt() Must return target values and target errnos. */
|
||||||
@ -1109,12 +1133,13 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
|
|||||||
msg.msg_iov = vec;
|
msg.msg_iov = vec;
|
||||||
|
|
||||||
if (send) {
|
if (send) {
|
||||||
target_to_host_cmsg(&msg, msgp);
|
ret = target_to_host_cmsg(&msg, msgp);
|
||||||
ret = get_errno(sendmsg(fd, &msg, flags));
|
if (ret == 0)
|
||||||
|
ret = get_errno(sendmsg(fd, &msg, flags));
|
||||||
} else {
|
} else {
|
||||||
ret = get_errno(recvmsg(fd, &msg, flags));
|
ret = get_errno(recvmsg(fd, &msg, flags));
|
||||||
if (!is_error(ret))
|
if (!is_error(ret))
|
||||||
host_to_target_cmsg(msgp, &msg);
|
ret = host_to_target_cmsg(msgp, &msg);
|
||||||
}
|
}
|
||||||
unlock_iovec(vec, target_vec, count, !send);
|
unlock_iovec(vec, target_vec, count, !send);
|
||||||
unlock_user_struct(msgp, target_msg, send ? 0 : 1);
|
unlock_user_struct(msgp, target_msg, send ? 0 : 1);
|
||||||
@ -1409,8 +1434,8 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
|
|||||||
#define N_SHM_REGIONS 32
|
#define N_SHM_REGIONS 32
|
||||||
|
|
||||||
static struct shm_region {
|
static struct shm_region {
|
||||||
uint32_t start;
|
abi_ulong start;
|
||||||
uint32_t size;
|
abi_ulong size;
|
||||||
} shm_regions[N_SHM_REGIONS];
|
} shm_regions[N_SHM_REGIONS];
|
||||||
|
|
||||||
struct target_ipc_perm
|
struct target_ipc_perm
|
||||||
@ -1776,7 +1801,6 @@ static abi_long do_ipc(unsigned int call, int first,
|
|||||||
{
|
{
|
||||||
int version;
|
int version;
|
||||||
abi_long ret = 0;
|
abi_long ret = 0;
|
||||||
unsigned long raddr;
|
|
||||||
struct shmid_ds shm_info;
|
struct shmid_ds shm_info;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -1831,32 +1855,38 @@ static abi_long do_ipc(unsigned int call, int first,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IPCOP_shmat:
|
case IPCOP_shmat:
|
||||||
/* SHM_* flags are the same on all linux platforms */
|
{
|
||||||
ret = get_errno((long) shmat(first, (void *) ptr, second));
|
abi_ulong raddr;
|
||||||
if (is_error(ret))
|
void *host_addr;
|
||||||
break;
|
/* SHM_* flags are the same on all linux platforms */
|
||||||
raddr = ret;
|
host_addr = shmat(first, (void *)g2h(ptr), second);
|
||||||
/* find out the length of the shared memory segment */
|
if (host_addr == (void *)-1) {
|
||||||
|
ret = get_errno((long)host_addr);
|
||||||
ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
|
|
||||||
if (is_error(ret)) {
|
|
||||||
/* can't get length, bail out */
|
|
||||||
shmdt((void *) raddr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
page_set_flags(raddr, raddr + shm_info.shm_segsz,
|
|
||||||
PAGE_VALID | PAGE_READ |
|
|
||||||
((second & SHM_RDONLY)? 0: PAGE_WRITE));
|
|
||||||
for (i = 0; i < N_SHM_REGIONS; ++i) {
|
|
||||||
if (shm_regions[i].start == 0) {
|
|
||||||
shm_regions[i].start = raddr;
|
|
||||||
shm_regions[i].size = shm_info.shm_segsz;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
raddr = h2g((unsigned long)host_addr);
|
||||||
if (put_user(raddr, third, abi_ulong))
|
/* find out the length of the shared memory segment */
|
||||||
return -TARGET_EFAULT;
|
|
||||||
ret = 0;
|
ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
|
||||||
|
if (is_error(ret)) {
|
||||||
|
/* can't get length, bail out */
|
||||||
|
shmdt(host_addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
page_set_flags(raddr, raddr + shm_info.shm_segsz,
|
||||||
|
PAGE_VALID | PAGE_READ |
|
||||||
|
((second & SHM_RDONLY)? 0: PAGE_WRITE));
|
||||||
|
for (i = 0; i < N_SHM_REGIONS; ++i) {
|
||||||
|
if (shm_regions[i].start == 0) {
|
||||||
|
shm_regions[i].start = raddr;
|
||||||
|
shm_regions[i].size = shm_info.shm_segsz;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (put_user(raddr, third, abi_ulong))
|
||||||
|
return -TARGET_EFAULT;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case IPCOP_shmdt:
|
case IPCOP_shmdt:
|
||||||
for (i = 0; i < N_SHM_REGIONS; ++i) {
|
for (i = 0; i < N_SHM_REGIONS; ++i) {
|
||||||
@ -1866,7 +1896,7 @@ static abi_long do_ipc(unsigned int call, int first,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret = get_errno(shmdt((void *) ptr));
|
ret = get_errno(shmdt((void *)g2h(ptr)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPCOP_shmget:
|
case IPCOP_shmget:
|
||||||
|
Loading…
Reference in New Issue
Block a user