aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-06 21:02:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-06 21:02:40 -0400
commit8529f613b6945f4b5bd8c1b69e42aa1cc51b2eb6 (patch)
treec8d29b5c266d90ddbaf3982b3863d64dc2be2ca4
parenta52dd971f947893bc7735396c74cfa591f0a7558 (diff)
vfs: don't force a big memset of stat data just to clear padding fields
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>
-rw-r--r--arch/x86/include/asm/stat.h21
-rw-r--r--fs/stat.c12
2 files changed, 31 insertions, 2 deletions
diff --git a/arch/x86/include/asm/stat.h b/arch/x86/include/asm/stat.h
index e0b1d9bbcbc6..7b3ddc348585 100644
--- a/arch/x86/include/asm/stat.h
+++ b/arch/x86/include/asm/stat.h
@@ -25,6 +25,12 @@ struct stat {
25 unsigned long __unused5; 25 unsigned long __unused5;
26}; 26};
27 27
28/* We don't need to memset the whole thing just to initialize the padding */
29#define INIT_STRUCT_STAT_PADDING(st) do { \
30 st.__unused4 = 0; \
31 st.__unused5 = 0; \
32} while (0)
33
28#define STAT64_HAS_BROKEN_ST_INO 1 34#define STAT64_HAS_BROKEN_ST_INO 1
29 35
30/* This matches struct stat64 in glibc2.1, hence the absolutely 36/* This matches struct stat64 in glibc2.1, hence the absolutely
@@ -63,6 +69,12 @@ struct stat64 {
63 unsigned long long st_ino; 69 unsigned long long st_ino;
64}; 70};
65 71
72/* We don't need to memset the whole thing just to initialize the padding */
73#define INIT_STRUCT_STAT64_PADDING(st) do { \
74 memset(&st.__pad0, 0, sizeof(st.__pad0)); \
75 memset(&st.__pad3, 0, sizeof(st.__pad3)); \
76} while (0)
77
66#else /* __i386__ */ 78#else /* __i386__ */
67 79
68struct stat { 80struct stat {
@@ -87,6 +99,15 @@ struct stat {
87 unsigned long st_ctime_nsec; 99 unsigned long st_ctime_nsec;
88 long __unused[3]; 100 long __unused[3];
89}; 101};
102
103/* We don't need to memset the whole thing just to initialize the padding */
104#define INIT_STRUCT_STAT_PADDING(st) do { \
105 st.__pad0 = 0; \
106 st.__unused[0] = 0; \
107 st.__unused[1] = 0; \
108 st.__unused[2] = 0; \
109} while (0)
110
90#endif 111#endif
91 112
92/* for 32bit emulation and 32 bit kernels */ 113/* for 32bit emulation and 32 bit kernels */
diff --git a/fs/stat.c b/fs/stat.c
index 2b5d55eb9d9a..b30ac60291e2 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -199,6 +199,10 @@ SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, stat
199#define valid_dev(x) choose_32_64(old_valid_dev,new_valid_dev)(x) 199#define valid_dev(x) choose_32_64(old_valid_dev,new_valid_dev)(x)
200#define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x) 200#define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x)
201 201
202#ifndef INIT_STRUCT_STAT_PADDING
203# define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st))
204#endif
205
202static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) 206static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
203{ 207{
204 struct stat tmp; 208 struct stat tmp;
@@ -210,7 +214,7 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
210 return -EOVERFLOW; 214 return -EOVERFLOW;
211#endif 215#endif
212 216
213 memset(&tmp, 0, sizeof(tmp)); 217 INIT_STRUCT_STAT_PADDING(tmp);
214 tmp.st_dev = encode_dev(stat->dev); 218 tmp.st_dev = encode_dev(stat->dev);
215 tmp.st_ino = stat->ino; 219 tmp.st_ino = stat->ino;
216 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 220 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,
323/* ---------- LFS-64 ----------- */ 327/* ---------- LFS-64 ----------- */
324#ifdef __ARCH_WANT_STAT64 328#ifdef __ARCH_WANT_STAT64
325 329
330#ifndef INIT_STRUCT_STAT64_PADDING
331# define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st))
332#endif
333
326static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) 334static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
327{ 335{
328 struct stat64 tmp; 336 struct stat64 tmp;
329 337
330 memset(&tmp, 0, sizeof(struct stat64)); 338 INIT_STRUCT_STAT64_PADDING(tmp);
331#ifdef CONFIG_MIPS 339#ifdef CONFIG_MIPS
332 /* mips has weird padding, so we don't get 64 bits there */ 340 /* mips has weird padding, so we don't get 64 bits there */
333 if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) 341 if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev))