From a52dd971f947893bc7735396c74cfa591f0a7558 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 May 2012 17:47:30 -0700 Subject: vfs: de-crapify "cp_new_stat()" function It's an unreadable mess of 32-bit vs 64-bit #ifdef's that mostly follow a rather simple pattern. Make a helper #define to handle that pattern, in the process making the code both shorter and more readable. Signed-off-by: Linus Torvalds --- fs/stat.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'fs/stat.c') diff --git a/fs/stat.c b/fs/stat.c index c733dc5753ae..2b5d55eb9d9a 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -190,24 +190,28 @@ SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, stat #endif /* __ARCH_WANT_OLD_STAT */ +#if BITS_PER_LONG == 32 +# define choose_32_64(a,b) a +#else +# define choose_32_64(a,b) b +#endif + +#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) + static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) { struct stat tmp; -#if BITS_PER_LONG == 32 - if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) + if (!valid_dev(stat->dev) || !valid_dev(stat->rdev)) return -EOVERFLOW; -#else - if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) +#if BITS_PER_LONG == 32 + if (stat->size > MAX_NON_LFS) return -EOVERFLOW; #endif memset(&tmp, 0, sizeof(tmp)); -#if BITS_PER_LONG == 32 - tmp.st_dev = old_encode_dev(stat->dev); -#else - tmp.st_dev = new_encode_dev(stat->dev); -#endif + 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) return -EOVERFLOW; @@ -217,15 +221,7 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) return -EOVERFLOW; SET_UID(tmp.st_uid, stat->uid); SET_GID(tmp.st_gid, stat->gid); -#if BITS_PER_LONG == 32 - tmp.st_rdev = old_encode_dev(stat->rdev); -#else - tmp.st_rdev = new_encode_dev(stat->rdev); -#endif -#if BITS_PER_LONG == 32 - if (stat->size > MAX_NON_LFS) - return -EOVERFLOW; -#endif + tmp.st_rdev = encode_dev(stat->rdev); tmp.st_size = stat->size; tmp.st_atime = stat->atime.tv_sec; tmp.st_mtime = stat->mtime.tv_sec; -- cgit v1.2.3-55-g7522 From 8529f613b6945f4b5bd8c1b69e42aa1cc51b2eb6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 May 2012 18:02:40 -0700 Subject: 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 --- arch/x86/include/asm/stat.h | 21 +++++++++++++++++++++ fs/stat.c | 12 ++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'fs/stat.c') 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 { 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 */ 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 #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)) -- cgit v1.2.3-55-g7522