Skip to content

Commit

Permalink
taskstats: pad taskstats netlink response for aligment issues on ia64
Browse files Browse the repository at this point in the history
The taskstats structure is internally aligned on 8 byte boundaries but the
layout of the aggregrate reply, with two NLA headers and the pid (each 4
bytes), actually force the entire structure to be unaligned.  This causes
the kernel to issue unaligned access warnings on some architectures like
ia64.  Unfortunately, some software out there doesn't properly unroll the
NLA packet and assumes that the start of the taskstats structure will
always be 20 bytes from the start of the netlink payload.  Aligning the
start of the taskstats structure breaks this software, which we don't
want.  So, for now the alignment only happens on architectures that
require it and those users will have to update to fixed versions of those
packages.  Space is reserved in the packet only when needed.  This ifdef
should be removed in several years e.g.  2012 once we can be confident
that fixed versions are installed on most systems.  We add the padding
before the aggregate since the aggregate is already a defined type.

Commit 8589312 ("delayacct: align to 8 byte boundary on 64-bit systems")
previously addressed the alignment issues by padding out the pid field.
This was supposed to be a compatible change but the circumstances
described above mean that it wasn't.  This patch backs out that change,
since it was a hack, and introduces a new NULL attribute type to provide
the padding.  Padding the response with 4 bytes avoids allocating an
aligned taskstats structure and copying it back.  Since the structure
weighs in at 328 bytes, it's too big to do it on the stack.

Signed-off-by: Jeff Mahoney <[email protected]>
Reported-by: Brian Rogers <[email protected]>
Cc: Jeff Mahoney <[email protected]>
Cc: Guillaume Chazarain <[email protected]>
Cc: Balbir Singh <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
jeffmahoney authored and torvalds committed Dec 23, 2010
1 parent 4e06fd1 commit 4be2c95
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 14 deletions.
1 change: 1 addition & 0 deletions Documentation/accounting/getdelays.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,7 @@ int main(int argc, char *argv[])
default:
fprintf(stderr, "Unknown nla_type %d\n",
na->nla_type);
case TASKSTATS_TYPE_NULL:
break;
}
na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
Expand Down
3 changes: 2 additions & 1 deletion include/linux/taskstats.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
*/


#define TASKSTATS_VERSION 7
#define TASKSTATS_VERSION 8
#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN
* in linux/sched.h */

Expand Down Expand Up @@ -188,6 +188,7 @@ enum {
TASKSTATS_TYPE_STATS, /* taskstats structure */
TASKSTATS_TYPE_AGGR_PID, /* contains pid + stats */
TASKSTATS_TYPE_AGGR_TGID, /* contains tgid + stats */
TASKSTATS_TYPE_NULL, /* contains nothing */
__TASKSTATS_TYPE_MAX,
};

Expand Down
57 changes: 44 additions & 13 deletions kernel/taskstats.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,25 +349,47 @@ static int parse(struct nlattr *na, struct cpumask *mask)
return ret;
}

#ifdef CONFIG_IA64
#define TASKSTATS_NEEDS_PADDING 1
#endif

static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid)
{
struct nlattr *na, *ret;
int aggr;

/* If we don't pad, we end up with alignment on a 4 byte boundary.
* This causes lots of runtime warnings on systems requiring 8 byte
* alignment */
u32 pids[2] = { pid, 0 };
int pid_size = ALIGN(sizeof(pid), sizeof(long));

aggr = (type == TASKSTATS_TYPE_PID)
? TASKSTATS_TYPE_AGGR_PID
: TASKSTATS_TYPE_AGGR_TGID;

/*
* The taskstats structure is internally aligned on 8 byte
* boundaries but the layout of the aggregrate reply, with
* two NLA headers and the pid (each 4 bytes), actually
* force the entire structure to be unaligned. This causes
* the kernel to issue unaligned access warnings on some
* architectures like ia64. Unfortunately, some software out there
* doesn't properly unroll the NLA packet and assumes that the start
* of the taskstats structure will always be 20 bytes from the start
* of the netlink payload. Aligning the start of the taskstats
* structure breaks this software, which we don't want. So, for now
* the alignment only happens on architectures that require it
* and those users will have to update to fixed versions of those
* packages. Space is reserved in the packet only when needed.
* This ifdef should be removed in several years e.g. 2012 once
* we can be confident that fixed versions are installed on most
* systems. We add the padding before the aggregate since the
* aggregate is already a defined type.
*/
#ifdef TASKSTATS_NEEDS_PADDING
if (nla_put(skb, TASKSTATS_TYPE_NULL, 0, NULL) < 0)
goto err;
#endif
na = nla_nest_start(skb, aggr);
if (!na)
goto err;
if (nla_put(skb, type, pid_size, pids) < 0)

if (nla_put(skb, type, sizeof(pid), &pid) < 0)
goto err;
ret = nla_reserve(skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats));
if (!ret)
Expand Down Expand Up @@ -456,6 +478,18 @@ static int cmd_attr_deregister_cpumask(struct genl_info *info)
return rc;
}

static size_t taskstats_packet_size(void)
{
size_t size;

size = nla_total_size(sizeof(u32)) +
nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
#ifdef TASKSTATS_NEEDS_PADDING
size += nla_total_size(0); /* Padding for alignment */
#endif
return size;
}

static int cmd_attr_pid(struct genl_info *info)
{
struct taskstats *stats;
Expand All @@ -464,8 +498,7 @@ static int cmd_attr_pid(struct genl_info *info)
u32 pid;
int rc;

size = nla_total_size(sizeof(u32)) +
nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
size = taskstats_packet_size();

rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
if (rc < 0)
Expand Down Expand Up @@ -494,8 +527,7 @@ static int cmd_attr_tgid(struct genl_info *info)
u32 tgid;
int rc;

size = nla_total_size(sizeof(u32)) +
nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
size = taskstats_packet_size();

rc = prepare_reply(info, TASKSTATS_CMD_NEW, &rep_skb, size);
if (rc < 0)
Expand Down Expand Up @@ -570,8 +602,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
/*
* Size includes space for nested attributes
*/
size = nla_total_size(sizeof(u32)) +
nla_total_size(sizeof(struct taskstats)) + nla_total_size(0);
size = taskstats_packet_size();

is_thread_group = !!taskstats_tgid_alloc(tsk);
if (is_thread_group) {
Expand Down

0 comments on commit 4be2c95

Please sign in to comment.