From: David van Moolenbroek Date: Thu, 20 Oct 2016 11:07:25 +0000 (+0000) Subject: RMIB: add support for vector copy-out X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=f221d2ce4807b04c41fa17e999402ee7bc5bf19c;p=minix.git RMIB: add support for vector copy-out Change-Id: I9e9b4b8d6eed39fdb511c6bd2a375ddf898064a5 --- diff --git a/minix/include/minix/rmib.h b/minix/include/minix/rmib.h index 0e055a404..06b403d8f 100644 --- a/minix/include/minix/rmib.h +++ b/minix/include/minix/rmib.h @@ -9,6 +9,12 @@ #include +/* + * The maximum number of I/O vector elements that can be passed to the + * rmib_vcopyout function. + */ +#define RMIB_IOV_MAX SCPVEC_NR + /* * This structure contains a number of less heavily used parameters for handler * functions, mainly to provide extensibility while limiting argument clutter. @@ -145,6 +151,8 @@ int rmib_inrange(struct rmib_oldp *, size_t); size_t rmib_getoldlen(struct rmib_oldp *); ssize_t rmib_copyout(struct rmib_oldp *, size_t, const void * __restrict, size_t); +ssize_t rmib_vcopyout(struct rmib_oldp *, size_t, const iovec_t *, + unsigned int); int rmib_copyin(struct rmib_newp * __restrict, void * __restrict, size_t); ssize_t rmib_readwrite(struct rmib_call *, struct rmib_node *, struct rmib_oldp *, struct rmib_newp *); diff --git a/minix/lib/libsys/rmib.c b/minix/lib/libsys/rmib.c index d14287efc..ad96e8644 100644 --- a/minix/lib/libsys/rmib.c +++ b/minix/lib/libsys/rmib.c @@ -110,6 +110,60 @@ rmib_copyout(struct rmib_oldp * __restrict oldp, size_t off, return size; } +/* + * Copy out (partial) data to the user, from a vector of up to RMIB_IOV_MAX + * local buffers. The copy is automatically limited to the range of data + * requested by the user. Return the total requested length on success or an + * error code on failure. + */ +ssize_t +rmib_vcopyout(struct rmib_oldp * oldp, size_t off, const iovec_t * iov, + unsigned int iovcnt) +{ + static struct vscp_vec vec[RMIB_IOV_MAX]; + size_t size, chunk; + unsigned int i; + ssize_t r; + + assert(iov != NULL); + assert(iovcnt <= __arraycount(vec)); + + /* Take a shortcut for single-vector elements, saving a kernel copy. */ + if (iovcnt == 1) + return rmib_copyout(oldp, off, (const void *)iov->iov_addr, + iov->iov_size); + + /* + * Iterate through the full vector even if we cannot copy out all of + * it, because we need to compute the total length. + */ + for (size = i = 0; iovcnt > 0; iov++, iovcnt--) { + if (oldp != NULL && off < oldp->oldp_len) { + chunk = oldp->oldp_len - off; + if (chunk > iov->iov_size) + chunk = iov->iov_size; + + vec[i].v_from = SELF; + vec[i].v_to = MIB_PROC_NR; + vec[i].v_gid = oldp->oldp_grant; + vec[i].v_offset = off; + vec[i].v_addr = iov->iov_addr; + vec[i].v_bytes = chunk; + + off += chunk; + i++; + } + + size += iov->iov_size; + } + + /* Perform the copy, if there is anything to copy, that is. */ + if (i > 0 && (r = sys_vsafecopy(vec, i)) != OK) + return r; + + return size; +} + /* * Copy in data from the user. The given length must match exactly the length * given by the user. Return OK or an error code. diff --git a/minix/net/inet/rtinfo.c b/minix/net/inet/rtinfo.c index 62f3880b0..7235abfa4 100644 --- a/minix/net/inet/rtinfo.c +++ b/minix/net/inet/rtinfo.c @@ -26,32 +26,6 @@ static const char padbuf[RT_ROUNDUP(0)] = { 0 }; -/* - * Copy out a vector of data to the sysctl(2) caller. TODO: decide what to do - * with this. We could implement this as a vectored-safecopy operation in - * RMIB. We could also copy everything into a single buffer first. The - * current implementation is probably the worst among the possibilities. - */ -static ssize_t -rmib_vcopyout(struct rmib_oldp * oldp, size_t off, const iovec_t * iov, - unsigned int iovcnt) -{ - unsigned int i; - ssize_t r, len; - - len = 0; - - for (i = 0; i < iovcnt; i++) { - if ((r = rmib_copyout(oldp, off + len, - (const void *)iov[i].iov_addr, iov[i].iov_size)) < 0) - return r; - - len += r; - } - - return len; -} - /* * Compute the length for, and possibly copy out, an interface information or * interface address record with an associated set of zero or more routing diff --git a/minix/net/lwip/rtinfo.c b/minix/net/lwip/rtinfo.c index 878fb3875..add6609a6 100644 --- a/minix/net/lwip/rtinfo.c +++ b/minix/net/lwip/rtinfo.c @@ -23,32 +23,6 @@ static const char padbuf[RT_ROUNDUP(0)] = { 0 }; -/* - * Copy out a vector of data to the sysctl(2) caller. TODO: decide what to do - * with this. We could implement this as a vectored-safecopy operation in - * RMIB. We could also copy everything into a single buffer first. The - * current implementation is probably the worst among the possibilities. - */ -static ssize_t -rmib_vcopyout(struct rmib_oldp * oldp, size_t off, const iovec_t * iov, - unsigned int iovcnt) -{ - unsigned int i; - ssize_t r, len; - - len = 0; - - for (i = 0; i < iovcnt; i++) { - if ((r = rmib_copyout(oldp, off + len, - (const void *)iov[i].iov_addr, iov[i].iov_size)) < 0) - return r; - - len += r; - } - - return len; -} - /* * Compute the length for, and possibly copy out, an interface information or * interface address record with an associated set of zero or more routing