Commit 20e7c361 authored by William Lee Irwin III's avatar William Lee Irwin III Committed by David S. Miller

[AIO]: kiocb->private is too large for kiocb's on-stack.

sizeof(struct kiocb) is dangerously large for a structure commonly
allocated on-stack. This patch converts the 24*sizeof(long) field,
->private, to a void pointer for use by file_operations entrypoints.
A ->dtor() method is added to the kiocb in order to support the release
of dynamically allocated structures referred to by ->private.

The sole in-tree users of ->private are async network read/write,
which are not, in fact, async, and so need not handle preallocated
->private as they would need to if ->ki_retry were ever used. The sole
truly async operations are direct IO pread()/pwrite() which do not
now use ->ki_retry(). All they would need to do in that case is to
check for ->private already being allocated for async kiocbs.

This rips 88B off the stack on 32-bit in the common case.
Signed-off-by: default avatarWilliam Lee Irwin III <wli@holomorphy.com>
Signed-off-by: default avatarDavid S. Miller <davem@redhat.com>
parent deaeb66a
...@@ -396,6 +396,8 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx) ...@@ -396,6 +396,8 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx)
req->ki_cancel = NULL; req->ki_cancel = NULL;
req->ki_retry = NULL; req->ki_retry = NULL;
req->ki_obj.user = NULL; req->ki_obj.user = NULL;
req->ki_dtor = NULL;
req->private = NULL;
/* Check if the completion queue has enough free space to /* Check if the completion queue has enough free space to
* accept an event from this io. * accept an event from this io.
...@@ -436,9 +438,13 @@ static inline struct kiocb *aio_get_req(struct kioctx *ctx) ...@@ -436,9 +438,13 @@ static inline struct kiocb *aio_get_req(struct kioctx *ctx)
static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
{ {
if (req->ki_dtor)
req->ki_dtor(req);
req->ki_ctx = NULL; req->ki_ctx = NULL;
req->ki_filp = NULL; req->ki_filp = NULL;
req->ki_obj.user = NULL; req->ki_obj.user = NULL;
req->ki_dtor = NULL;
req->private = NULL;
kmem_cache_free(kiocb_cachep, req); kmem_cache_free(kiocb_cachep, req);
ctx->reqs_active--; ctx->reqs_active--;
......
...@@ -23,8 +23,6 @@ struct kioctx; ...@@ -23,8 +23,6 @@ struct kioctx;
#define KIOCB_SYNC_KEY (~0U) #define KIOCB_SYNC_KEY (~0U)
#define KIOCB_PRIVATE_SIZE (24 * sizeof(long))
/* ki_flags bits */ /* ki_flags bits */
#define KIF_LOCKED 0 #define KIF_LOCKED 0
#define KIF_KICKED 1 #define KIF_KICKED 1
...@@ -55,6 +53,7 @@ struct kiocb { ...@@ -55,6 +53,7 @@ struct kiocb {
struct kioctx *ki_ctx; /* may be NULL for sync ops */ struct kioctx *ki_ctx; /* may be NULL for sync ops */
int (*ki_cancel)(struct kiocb *, struct io_event *); int (*ki_cancel)(struct kiocb *, struct io_event *);
long (*ki_retry)(struct kiocb *); long (*ki_retry)(struct kiocb *);
void (*ki_dtor)(struct kiocb *);
struct list_head ki_list; /* the aio core uses this struct list_head ki_list; /* the aio core uses this
* for cancellation */ * for cancellation */
...@@ -65,8 +64,7 @@ struct kiocb { ...@@ -65,8 +64,7 @@ struct kiocb {
} ki_obj; } ki_obj;
__u64 ki_user_data; /* user's data for completion */ __u64 ki_user_data; /* user's data for completion */
loff_t ki_pos; loff_t ki_pos;
void *private;
char private[KIOCB_PRIVATE_SIZE];
}; };
#define is_sync_kiocb(iocb) ((iocb)->ki_key == KIOCB_SYNC_KEY) #define is_sync_kiocb(iocb) ((iocb)->ki_key == KIOCB_SYNC_KEY)
...@@ -79,6 +77,7 @@ struct kiocb { ...@@ -79,6 +77,7 @@ struct kiocb {
(x)->ki_filp = (filp); \ (x)->ki_filp = (filp); \
(x)->ki_ctx = &tsk->active_mm->default_kioctx; \ (x)->ki_ctx = &tsk->active_mm->default_kioctx; \
(x)->ki_cancel = NULL; \ (x)->ki_cancel = NULL; \
(x)->ki_dtor = NULL; \
(x)->ki_obj.tsk = tsk; \ (x)->ki_obj.tsk = tsk; \
} while (0) } while (0)
......
...@@ -617,17 +617,17 @@ struct sock_iocb { ...@@ -617,17 +617,17 @@ struct sock_iocb {
struct scm_cookie *scm; struct scm_cookie *scm;
struct msghdr *msg, async_msg; struct msghdr *msg, async_msg;
struct iovec async_iov; struct iovec async_iov;
struct kiocb *kiocb;
}; };
static inline struct sock_iocb *kiocb_to_siocb(struct kiocb *iocb) static inline struct sock_iocb *kiocb_to_siocb(struct kiocb *iocb)
{ {
BUG_ON(sizeof(struct sock_iocb) > KIOCB_PRIVATE_SIZE);
return (struct sock_iocb *)iocb->private; return (struct sock_iocb *)iocb->private;
} }
static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si) static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si)
{ {
return container_of((void *)si, struct kiocb, private); return si->kiocb;
} }
struct socket_alloc { struct socket_alloc {
......
...@@ -548,9 +548,11 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -548,9 +548,11 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
{ {
struct kiocb iocb; struct kiocb iocb;
struct sock_iocb siocb;
int ret; int ret;
init_sync_kiocb(&iocb, NULL); init_sync_kiocb(&iocb, NULL);
iocb.private = &siocb;
ret = __sock_sendmsg(&iocb, sock, msg, size); ret = __sock_sendmsg(&iocb, sock, msg, size);
if (-EIOCBQUEUED == ret) if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&iocb); ret = wait_on_sync_kiocb(&iocb);
...@@ -581,15 +583,22 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg, ...@@ -581,15 +583,22 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
size_t size, int flags) size_t size, int flags)
{ {
struct kiocb iocb; struct kiocb iocb;
struct sock_iocb siocb;
int ret; int ret;
init_sync_kiocb(&iocb, NULL); init_sync_kiocb(&iocb, NULL);
iocb.private = &siocb;
ret = __sock_recvmsg(&iocb, sock, msg, size, flags); ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
if (-EIOCBQUEUED == ret) if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&iocb); ret = wait_on_sync_kiocb(&iocb);
return ret; return ret;
} }
static void sock_aio_dtor(struct kiocb *iocb)
{
kfree(iocb->private);
}
/* /*
* Read data from a socket. ubuf is a user mode pointer. We make sure the user * Read data from a socket. ubuf is a user mode pointer. We make sure the user
* area ubuf...ubuf+size-1 is writable before asking the protocol. * area ubuf...ubuf+size-1 is writable before asking the protocol.
...@@ -598,7 +607,7 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg, ...@@ -598,7 +607,7 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
size_t size, loff_t pos) size_t size, loff_t pos)
{ {
struct sock_iocb *x = kiocb_to_siocb(iocb); struct sock_iocb *x, siocb;
struct socket *sock; struct socket *sock;
int flags; int flags;
...@@ -607,6 +616,16 @@ static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, ...@@ -607,6 +616,16 @@ static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
if (size==0) /* Match SYS5 behaviour */ if (size==0) /* Match SYS5 behaviour */
return 0; return 0;
if (is_sync_kiocb(iocb))
x = &siocb;
else {
x = kmalloc(sizeof(struct sock_iocb), GFP_KERNEL);
if (!x)
return -ENOMEM;
iocb->ki_dtor = sock_aio_dtor;
}
iocb->private = x;
x->kiocb = iocb;
sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode); sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode);
x->async_msg.msg_name = NULL; x->async_msg.msg_name = NULL;
...@@ -631,7 +650,7 @@ static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, ...@@ -631,7 +650,7 @@ static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
size_t size, loff_t pos) size_t size, loff_t pos)
{ {
struct sock_iocb *x = kiocb_to_siocb(iocb); struct sock_iocb *x, siocb;
struct socket *sock; struct socket *sock;
if (pos != 0) if (pos != 0)
...@@ -639,6 +658,16 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, ...@@ -639,6 +658,16 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
if(size==0) /* Match SYS5 behaviour */ if(size==0) /* Match SYS5 behaviour */
return 0; return 0;
if (is_sync_kiocb(iocb))
x = &siocb;
else {
x = kmalloc(sizeof(struct sock_iocb), GFP_KERNEL);
if (!x)
return -ENOMEM;
iocb->ki_dtor = sock_aio_dtor;
}
iocb->private = x;
x->kiocb = iocb;
sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode); sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode);
x->async_msg.msg_name = NULL; x->async_msg.msg_name = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment