Commit 41a9f1f6 authored by Jeff Layton's avatar Jeff Layton Committed by Steve French

cifs: avoid extra allocation for small cifs.idmap keys

The cifs.idmap keytype always allocates memory to hold the payload from
userspace. In the common case where we're translating a SID to a UID or
GID, we're allocating memory to hold something that's less than or equal
to the size of a pointer.

When the payload is the same size as a pointer or smaller, just store
it in the payload.value union member instead. That saves us an extra
allocation on the sid_to_id upcall.

Note that we have to take extra care to check the datalen when we
go to dereference the .data pointer in the union, but the callers
now check that as a matter of course anyway.
Reviewed-by: default avatarShirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent faa65f07
...@@ -49,6 +49,20 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep) ...@@ -49,6 +49,20 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{ {
char *payload; char *payload;
/*
* If the payload is less than or equal to the size of a pointer, then
* an allocation here is wasteful. Just copy the data directly to the
* payload.value union member instead.
*
* With this however, you must check the datalen before trying to
* dereference payload.data!
*/
if (prep->datalen <= sizeof(void *)) {
key->payload.value = 0;
memcpy(&key->payload.value, prep->data, prep->datalen);
key->datalen = prep->datalen;
return 0;
}
payload = kmalloc(prep->datalen, GFP_KERNEL); payload = kmalloc(prep->datalen, GFP_KERNEL);
if (!payload) if (!payload)
return -ENOMEM; return -ENOMEM;
...@@ -62,7 +76,8 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep) ...@@ -62,7 +76,8 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
static inline void static inline void
cifs_idmap_key_destroy(struct key *key) cifs_idmap_key_destroy(struct key *key)
{ {
kfree(key->payload.data); if (key->datalen > sizeof(void *))
kfree(key->payload.data);
} }
static struct key_type cifs_idmap_key_type = { static struct key_type cifs_idmap_key_type = {
...@@ -245,7 +260,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, ...@@ -245,7 +260,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
* probably a safe assumption but might be better to check based on * probably a safe assumption but might be better to check based on
* sidtype. * sidtype.
*/ */
if (sidkey->datalen < sizeof(uid_t)) { if (sidkey->datalen != sizeof(uid_t)) {
rc = -EIO; rc = -EIO;
cFYI(1, "%s: Downcall contained malformed key " cFYI(1, "%s: Downcall contained malformed key "
"(datalen=%hu)", __func__, sidkey->datalen); "(datalen=%hu)", __func__, sidkey->datalen);
...@@ -253,9 +268,9 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, ...@@ -253,9 +268,9 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
} }
if (sidtype == SIDOWNER) if (sidtype == SIDOWNER)
fuid = *(uid_t *)sidkey->payload.value; memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t));
else else
fgid = *(gid_t *)sidkey->payload.value; memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t));
out_key_put: out_key_put:
key_put(sidkey); key_put(sidkey);
......
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