]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
vfs: don't force a big memset of stat data just to clear padding fields
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 7 May 2012 01:02:40 +0000 (18:02 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 7 May 2012 01:02:40 +0000 (18:02 -0700)
Admittedly this is something that the compiler should be able to just do
for us, but gcc just isn't that smart.  And trying to use a structure
initializer (which would get us the right semantics) ends up resulting
in gcc allocating stack space for _two_ 'struct stat', and then copying
one into the other.

So do it by hand - just have a per-architecture macro that initializes
the padding fields.  And if the architecture doesn't provide one, fall
back to the old behavior of just doing the whole memset() first.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/x86/include/asm/stat.h
fs/stat.c

index e0b1d9bbcbc66b2b1717949537795c2688cd09bc..7b3ddc348585f0c8b4cc0afe63b6ac36206217d3 100644 (file)
@@ -25,6 +25,12 @@ struct stat {
        unsigned long  __unused5;
 };
 
+/* We don't need to memset the whole thing just to initialize the padding */
+#define INIT_STRUCT_STAT_PADDING(st) do {      \
+       st.__unused4 = 0;                       \
+       st.__unused5 = 0;                       \
+} while (0)
+
 #define STAT64_HAS_BROKEN_ST_INO       1
 
 /* This matches struct stat64 in glibc2.1, hence the absolutely
@@ -63,6 +69,12 @@ struct stat64 {
        unsigned long long      st_ino;
 };
 
+/* We don't need to memset the whole thing just to initialize the padding */
+#define INIT_STRUCT_STAT64_PADDING(st) do {            \
+       memset(&st.__pad0, 0, sizeof(st.__pad0));       \
+       memset(&st.__pad3, 0, sizeof(st.__pad3));       \
+} while (0)
+
 #else /* __i386__ */
 
 struct stat {
@@ -87,6 +99,15 @@ struct stat {
        unsigned long   st_ctime_nsec;
        long            __unused[3];
 };
+
+/* We don't need to memset the whole thing just to initialize the padding */
+#define INIT_STRUCT_STAT_PADDING(st) do {      \
+       st.__pad0 = 0;                          \
+       st.__unused[0] = 0;                     \
+       st.__unused[1] = 0;                     \
+       st.__unused[2] = 0;                     \
+} while (0)
+
 #endif
 
 /* for 32bit emulation and 32 bit kernels */
index 2b5d55eb9d9a3048acab8963ec1c1acd365f6f02..b30ac60291e273bbdf833f4f51da20032bd2f587 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -199,6 +199,10 @@ SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, stat
 #define valid_dev(x)  choose_32_64(old_valid_dev,new_valid_dev)(x)
 #define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x)
 
+#ifndef INIT_STRUCT_STAT_PADDING
+#  define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st))
+#endif
+
 static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
 {
        struct stat tmp;
@@ -210,7 +214,7 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
                return -EOVERFLOW;
 #endif
 
-       memset(&tmp, 0, sizeof(tmp));
+       INIT_STRUCT_STAT_PADDING(tmp);
        tmp.st_dev = encode_dev(stat->dev);
        tmp.st_ino = stat->ino;
        if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
@@ -323,11 +327,15 @@ SYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf,
 /* ---------- LFS-64 ----------- */
 #ifdef __ARCH_WANT_STAT64
 
+#ifndef INIT_STRUCT_STAT64_PADDING
+#  define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st))
+#endif
+
 static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
 {
        struct stat64 tmp;
 
-       memset(&tmp, 0, sizeof(struct stat64));
+       INIT_STRUCT_STAT64_PADDING(tmp);
 #ifdef CONFIG_MIPS
        /* mips has weird padding, so we don't get 64 bits there */
        if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev))