rxrpc: Don't expose skbs to in-kernel users [ver #2]
Don't expose skbs to in-kernel users, such as the AFS filesystem, but instead provide a notification hook the indicates that a call needs attention and another that indicates that there's a new call to be collected. This makes the following possibilities more achievable: (1) Call refcounting can be made simpler if skbs don't hold refs to calls. (2) skbs referring to non-data events will be able to be freed much sooner rather than being queued for AFS to pick up as rxrpc_kernel_recv_data will be able to consult the call state. (3) We can shortcut the receive phase when a call is remotely aborted because we don't have to go through all the packets to get to the one cancelling the operation. (4) It makes it easier to do encryption/decryption directly between AFS's buffers and sk_buffs. (5) Encryption/decryption can more easily be done in the AFS's thread contexts - usually that of the userspace process that issued a syscall - rather than in one of rxrpc's background threads on a workqueue. (6) AFS will be able to wait synchronously on a call inside AF_RXRPC. To make this work, the following interface function has been added: int rxrpc_kernel_recv_data( struct socket *sock, struct rxrpc_call *call, void *buffer, size_t bufsize, size_t *_offset, bool want_more, u32 *_abort_code); This is the recvmsg equivalent. It allows the caller to find out about the state of a specific call and to transfer received data into a buffer piecemeal. afs_extract_data() and rxrpc_kernel_recv_data() now do all the extraction logic between them. They don't wait synchronously yet because the socket lock needs to be dealt with. Five interface functions have been removed: rxrpc_kernel_is_data_last() rxrpc_kernel_get_abort_code() rxrpc_kernel_get_error_number() rxrpc_kernel_free_skb() rxrpc_kernel_data_consumed() As a temporary hack, sk_buffs going to an in-kernel call are queued on the rxrpc_call struct (->knlrecv_queue) rather than being handed over to the in-kernel user. To process the queue internally, a temporary function, temp_deliver_data() has been added. This will be replaced with common code between the rxrpc_recvmsg() path and the kernel_rxrpc_recv_data() path in a future patch. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
95ac399451
commit
d001648ec7
@@ -235,16 +235,15 @@ static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
|
||||
/*
|
||||
* deliver reply data to an FS.FetchStatus
|
||||
*/
|
||||
static int afs_deliver_fs_fetch_status(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_fetch_status(struct afs_call *call)
|
||||
{
|
||||
struct afs_vnode *vnode = call->reply;
|
||||
const __be32 *bp;
|
||||
int ret;
|
||||
|
||||
_enter(",,%u", last);
|
||||
_enter("");
|
||||
|
||||
ret = afs_transfer_reply(call, skb, last);
|
||||
ret = afs_transfer_reply(call);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -307,8 +306,7 @@ int afs_fs_fetch_file_status(struct afs_server *server,
|
||||
/*
|
||||
* deliver reply data to an FS.FetchData
|
||||
*/
|
||||
static int afs_deliver_fs_fetch_data(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_fetch_data(struct afs_call *call)
|
||||
{
|
||||
struct afs_vnode *vnode = call->reply;
|
||||
const __be32 *bp;
|
||||
@@ -316,7 +314,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
|
||||
void *buffer;
|
||||
int ret;
|
||||
|
||||
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
||||
_enter("{%u}", call->unmarshall);
|
||||
|
||||
switch (call->unmarshall) {
|
||||
case 0:
|
||||
@@ -332,7 +330,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
|
||||
* client) */
|
||||
case 1:
|
||||
_debug("extract data length (MSW)");
|
||||
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -347,7 +345,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
|
||||
/* extract the returned data length */
|
||||
case 2:
|
||||
_debug("extract data length");
|
||||
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -363,10 +361,10 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
|
||||
_debug("extract data");
|
||||
if (call->count > 0) {
|
||||
page = call->reply3;
|
||||
buffer = kmap_atomic(page);
|
||||
ret = afs_extract_data(call, skb, last, buffer,
|
||||
call->count);
|
||||
kunmap_atomic(buffer);
|
||||
buffer = kmap(page);
|
||||
ret = afs_extract_data(call, buffer,
|
||||
call->count, true);
|
||||
kunmap(buffer);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -376,8 +374,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
|
||||
|
||||
/* extract the metadata */
|
||||
case 4:
|
||||
ret = afs_extract_data(call, skb, last, call->buffer,
|
||||
(21 + 3 + 6) * 4);
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
(21 + 3 + 6) * 4, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -391,18 +389,15 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
|
||||
call->unmarshall++;
|
||||
|
||||
case 5:
|
||||
ret = afs_data_complete(call, skb, last);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
if (call->count < PAGE_SIZE) {
|
||||
_debug("clear");
|
||||
page = call->reply3;
|
||||
buffer = kmap_atomic(page);
|
||||
buffer = kmap(page);
|
||||
memset(buffer + call->count, 0, PAGE_SIZE - call->count);
|
||||
kunmap_atomic(buffer);
|
||||
kunmap(buffer);
|
||||
}
|
||||
|
||||
_leave(" = 0 [done]");
|
||||
@@ -515,13 +510,12 @@ int afs_fs_fetch_data(struct afs_server *server,
|
||||
/*
|
||||
* deliver reply data to an FS.GiveUpCallBacks
|
||||
*/
|
||||
static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_give_up_callbacks(struct afs_call *call)
|
||||
{
|
||||
_enter(",{%u},%d", skb->len, last);
|
||||
_enter("");
|
||||
|
||||
/* shouldn't be any reply data */
|
||||
return afs_data_complete(call, skb, last);
|
||||
return afs_extract_data(call, NULL, 0, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -599,16 +593,15 @@ int afs_fs_give_up_callbacks(struct afs_server *server,
|
||||
/*
|
||||
* deliver reply data to an FS.CreateFile or an FS.MakeDir
|
||||
*/
|
||||
static int afs_deliver_fs_create_vnode(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_create_vnode(struct afs_call *call)
|
||||
{
|
||||
struct afs_vnode *vnode = call->reply;
|
||||
const __be32 *bp;
|
||||
int ret;
|
||||
|
||||
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
||||
_enter("{%u}", call->unmarshall);
|
||||
|
||||
ret = afs_transfer_reply(call, skb, last);
|
||||
ret = afs_transfer_reply(call);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -696,16 +689,15 @@ int afs_fs_create(struct afs_server *server,
|
||||
/*
|
||||
* deliver reply data to an FS.RemoveFile or FS.RemoveDir
|
||||
*/
|
||||
static int afs_deliver_fs_remove(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_remove(struct afs_call *call)
|
||||
{
|
||||
struct afs_vnode *vnode = call->reply;
|
||||
const __be32 *bp;
|
||||
int ret;
|
||||
|
||||
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
||||
_enter("{%u}", call->unmarshall);
|
||||
|
||||
ret = afs_transfer_reply(call, skb, last);
|
||||
ret = afs_transfer_reply(call);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -777,16 +769,15 @@ int afs_fs_remove(struct afs_server *server,
|
||||
/*
|
||||
* deliver reply data to an FS.Link
|
||||
*/
|
||||
static int afs_deliver_fs_link(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_link(struct afs_call *call)
|
||||
{
|
||||
struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
|
||||
const __be32 *bp;
|
||||
int ret;
|
||||
|
||||
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
||||
_enter("{%u}", call->unmarshall);
|
||||
|
||||
ret = afs_transfer_reply(call, skb, last);
|
||||
ret = afs_transfer_reply(call);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -863,16 +854,15 @@ int afs_fs_link(struct afs_server *server,
|
||||
/*
|
||||
* deliver reply data to an FS.Symlink
|
||||
*/
|
||||
static int afs_deliver_fs_symlink(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_symlink(struct afs_call *call)
|
||||
{
|
||||
struct afs_vnode *vnode = call->reply;
|
||||
const __be32 *bp;
|
||||
int ret;
|
||||
|
||||
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
||||
_enter("{%u}", call->unmarshall);
|
||||
|
||||
ret = afs_transfer_reply(call, skb, last);
|
||||
ret = afs_transfer_reply(call);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -968,16 +958,15 @@ int afs_fs_symlink(struct afs_server *server,
|
||||
/*
|
||||
* deliver reply data to an FS.Rename
|
||||
*/
|
||||
static int afs_deliver_fs_rename(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_rename(struct afs_call *call)
|
||||
{
|
||||
struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
|
||||
const __be32 *bp;
|
||||
int ret;
|
||||
|
||||
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
||||
_enter("{%u}", call->unmarshall);
|
||||
|
||||
ret = afs_transfer_reply(call, skb, last);
|
||||
ret = afs_transfer_reply(call);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1072,16 +1061,15 @@ int afs_fs_rename(struct afs_server *server,
|
||||
/*
|
||||
* deliver reply data to an FS.StoreData
|
||||
*/
|
||||
static int afs_deliver_fs_store_data(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_store_data(struct afs_call *call)
|
||||
{
|
||||
struct afs_vnode *vnode = call->reply;
|
||||
const __be32 *bp;
|
||||
int ret;
|
||||
|
||||
_enter(",,%u", last);
|
||||
_enter("");
|
||||
|
||||
ret = afs_transfer_reply(call, skb, last);
|
||||
ret = afs_transfer_reply(call);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1251,17 +1239,16 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
|
||||
/*
|
||||
* deliver reply data to an FS.StoreStatus
|
||||
*/
|
||||
static int afs_deliver_fs_store_status(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_store_status(struct afs_call *call)
|
||||
{
|
||||
afs_dataversion_t *store_version;
|
||||
struct afs_vnode *vnode = call->reply;
|
||||
const __be32 *bp;
|
||||
int ret;
|
||||
|
||||
_enter(",,%u", last);
|
||||
_enter("");
|
||||
|
||||
ret = afs_transfer_reply(call, skb, last);
|
||||
ret = afs_transfer_reply(call);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1443,14 +1430,13 @@ int afs_fs_setattr(struct afs_server *server, struct key *key,
|
||||
/*
|
||||
* deliver reply data to an FS.GetVolumeStatus
|
||||
*/
|
||||
static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_get_volume_status(struct afs_call *call)
|
||||
{
|
||||
const __be32 *bp;
|
||||
char *p;
|
||||
int ret;
|
||||
|
||||
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
||||
_enter("{%u}", call->unmarshall);
|
||||
|
||||
switch (call->unmarshall) {
|
||||
case 0:
|
||||
@@ -1460,8 +1446,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
/* extract the returned status record */
|
||||
case 1:
|
||||
_debug("extract status");
|
||||
ret = afs_extract_data(call, skb, last, call->buffer,
|
||||
12 * 4);
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
12 * 4, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1472,7 +1458,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
|
||||
/* extract the volume name length */
|
||||
case 2:
|
||||
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1487,8 +1473,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
case 3:
|
||||
_debug("extract volname");
|
||||
if (call->count > 0) {
|
||||
ret = afs_extract_data(call, skb, last, call->reply3,
|
||||
call->count);
|
||||
ret = afs_extract_data(call, call->reply3,
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -1508,8 +1494,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
call->count = 4 - (call->count & 3);
|
||||
|
||||
case 4:
|
||||
ret = afs_extract_data(call, skb, last, call->buffer,
|
||||
call->count);
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1519,7 +1505,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
|
||||
/* extract the offline message length */
|
||||
case 5:
|
||||
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1534,8 +1520,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
case 6:
|
||||
_debug("extract offline");
|
||||
if (call->count > 0) {
|
||||
ret = afs_extract_data(call, skb, last, call->reply3,
|
||||
call->count);
|
||||
ret = afs_extract_data(call, call->reply3,
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -1555,8 +1541,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
call->count = 4 - (call->count & 3);
|
||||
|
||||
case 7:
|
||||
ret = afs_extract_data(call, skb, last, call->buffer,
|
||||
call->count);
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1566,7 +1552,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
|
||||
/* extract the message of the day length */
|
||||
case 8:
|
||||
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1581,8 +1567,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
case 9:
|
||||
_debug("extract motd");
|
||||
if (call->count > 0) {
|
||||
ret = afs_extract_data(call, skb, last, call->reply3,
|
||||
call->count);
|
||||
ret = afs_extract_data(call, call->reply3,
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -1595,26 +1581,17 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
||||
call->unmarshall++;
|
||||
|
||||
/* extract the message of the day padding */
|
||||
if ((call->count & 3) == 0) {
|
||||
call->unmarshall++;
|
||||
goto no_motd_padding;
|
||||
}
|
||||
call->count = 4 - (call->count & 3);
|
||||
call->count = (4 - (call->count & 3)) & 3;
|
||||
|
||||
case 10:
|
||||
ret = afs_extract_data(call, skb, last, call->buffer,
|
||||
call->count);
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
call->count, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
no_motd_padding:
|
||||
|
||||
case 11:
|
||||
ret = afs_data_complete(call, skb, last);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1685,15 +1662,14 @@ int afs_fs_get_volume_status(struct afs_server *server,
|
||||
/*
|
||||
* deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
|
||||
*/
|
||||
static int afs_deliver_fs_xxxx_lock(struct afs_call *call,
|
||||
struct sk_buff *skb, bool last)
|
||||
static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
|
||||
{
|
||||
const __be32 *bp;
|
||||
int ret;
|
||||
|
||||
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
||||
_enter("{%u}", call->unmarshall);
|
||||
|
||||
ret = afs_transfer_reply(call, skb, last);
|
||||
ret = afs_transfer_reply(call);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
Reference in New Issue
Block a user