Home | History | Annotate | Download | only in patches
      1 From ec19461cecdac81c48bbbe4783624167754349a2 Mon Sep 17 00:00:00 2001
      2 From: Mike Frysinger <vapier (a] gentoo.org>
      3 Date: Thu, 8 Mar 2012 17:40:52 -0500
      4 Subject: [PATCH] getdents: rewrite syscall handling completely
      5 
      6 The inline asm has many problems, but rather than attempt to fix
      7 them, just use syscall() for everyone.  This allows us to drop the
      8 i386-specific checks and have the tests run on all arches.
      9 
     10 Further, add a layer between the kernel and the dirent struct that
     11 the tests uses.  The kernel packs the results, so we need to expand
     12 the raw buffer returned by the kernel into the userland structs we
     13 pass around.
     14 
     15 Signed-off-by: Mike Frysinger <vapier (a] gentoo.org>
     16 ---
     17  testcases/kernel/syscalls/getdents/getdents.h   |   73 +++++++++++++++++------
     18  testcases/kernel/syscalls/getdents/getdents01.c |   20 +-----
     19  testcases/kernel/syscalls/getdents/getdents02.c |   27 +--------
     20  testcases/kernel/syscalls/getdents/getdents03.c |   27 +--------
     21  testcases/kernel/syscalls/getdents/getdents04.c |   26 +-------
     22  5 files changed, 67 insertions(+), 106 deletions(-)
     23 
     24 diff --git a/testcases/kernel/syscalls/getdents/getdents.h b/testcases/kernel/syscalls/getdents/getdents.h
     25 index 3ab3fd2..a5ddfea 100644
     26 --- a/testcases/kernel/syscalls/getdents/getdents.h
     27 +++ b/testcases/kernel/syscalls/getdents/getdents.h
     28 @@ -23,25 +23,62 @@
     29  
     30  #ifndef __GETDENTS_H
     31  #define __GETDENTS_H	1
     32 +
     33 +#include <dirent.h>
     34 +#include <stdio.h>
     35 +#include <string.h>
     36 +#include <unistd.h>
     37  #include <sys/syscall.h>
     38  
     39 -#ifdef __i386__
     40 -	#define GETDENTS_ASM() ({ int __rval;				\
     41 -				__asm__ __volatile__("			\
     42 -					movl	%4, %%edx \n		\
     43 -					movl	%3, %%ecx \n		\
     44 -					movl	%2, %%ebx \n		\
     45 -					movl	%1, %%eax \n		\
     46 -					int	$0x80 \n		\
     47 -					movl	%%eax, %0"		\
     48 -				: "=a" (__rval)				\
     49 -				: "a" (cnum), "b" (fd), "c" (dirp), "d" (count)\
     50 -				: "memory"				\
     51 -				);					\
     52 -				__rval;					\
     53 -		    	})
     54 -#else
     55 -	#define GETDENTS_ASM() 0
     56 -#endif /* __i386__ */
     57 +/*
     58 + * The dirent struct that the C library exports is not the same
     59 + * as the kernel ABI, so we can't include dirent.h and use the
     60 + * dirent struct from there.  Further, since the Linux headers
     61 + * don't export their vision of the struct either, we have to
     62 + * declare our own here.  Wheeeeee.
     63 + */
     64 +
     65 +struct linux_dirent {
     66 +	unsigned long   d_ino;
     67 +	unsigned long   d_off;
     68 +	unsigned short  d_reclen;
     69 +	char            d_name[];
     70 +};
     71 +
     72 +static inline int
     73 +getdents(unsigned int fd, struct dirent *dirp, unsigned int count)
     74 +{
     75 +	union {
     76 +		struct linux_dirent *dirp;
     77 +		char *buf;
     78 +	} ptrs;
     79 +	char buf[count];
     80 +	long ret;
     81 +	unsigned int i;
     82 +
     83 +	ptrs.buf = buf;
     84 +	ret = syscall(SYS_getdents, fd, buf, count);
     85 +	if (ret < 0)
     86 +		return ret;
     87 +
     88 +#define kdircpy(field) memcpy(&dirp[i].field, &ptrs.dirp->field, sizeof(dirp[i].field))
     89 +
     90 +	i = 0;
     91 +	while (i < count && i < ret) {
     92 +		unsigned long reclen;
     93 +
     94 +		kdircpy(d_ino);
     95 +		kdircpy(d_reclen);
     96 +		reclen = dirp[i].d_reclen;
     97 +		kdircpy(d_off);
     98 +		strcpy(dirp[i].d_name, ptrs.dirp->d_name);
     99 +
    100 +		ptrs.buf += reclen;
    101 +
    102 +		i += reclen;
    103 +	}
    104 +
    105 +	return ret;
    106 +}
    107  
    108  #endif /* getdents.h */
    109 diff --git a/testcases/kernel/syscalls/getdents/getdents01.c b/testcases/kernel/syscalls/getdents/getdents01.c
    110 index 266a9c0..8afb08a 100644
    111 --- a/testcases/kernel/syscalls/getdents/getdents01.c
    112 +++ b/testcases/kernel/syscalls/getdents/getdents01.c
    113 @@ -81,17 +81,6 @@ int main(int ac, char **av)
    114  	char *dir_name = NULL;
    115  	struct dirent *dirp;
    116  
    117 -	/*
    118 -	 * Here's a case where invoking the system call directly
    119 -	 * doesn't seem to work.  getdents.h has an assembly
    120 -	 * macro to do the job.
    121 -	 *
    122 -	 * equivalent to  - getdents(fd, dirp, count);
    123 -	 * if we could call getdents that way.
    124 -	 */
    125 -
    126 -#define getdents(arg1, arg2, arg3) syscall(__NR_getdents, arg1, arg2, arg3)
    127 -
    128  	if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
    129  		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
    130  
    131 @@ -120,17 +109,14 @@ int main(int ac, char **av)
    132  		rval = getdents(fd, dirp, count);
    133  		if (rval < 0) {
    134  
    135 -			rval *= -1;
    136 -			TEST_ERROR_LOG(rval);
    137 +			TEST_ERROR_LOG(errno);
    138  
    139 -			tst_resm(TFAIL, "%s call failed - errno = %d "
    140 -				 ": %s", TCID, rval, strerror(rval));
    141 +			tst_resm(TFAIL|TERRNO, "getdents failed unexpectedly");
    142  			continue;
    143  		}
    144  
    145  		if (rval == 0) {
    146 -			tst_resm(TFAIL, "%s call failed - returned "
    147 -				 "end of directory", TCID);
    148 +			tst_resm(TFAIL, "getdents failed - returned end of directory");
    149  			continue;
    150  		}
    151  
    152 diff --git a/testcases/kernel/syscalls/getdents/getdents02.c b/testcases/kernel/syscalls/getdents/getdents02.c
    153 index 46d1133..af826d1 100644
    154 --- a/testcases/kernel/syscalls/getdents/getdents02.c
    155 +++ b/testcases/kernel/syscalls/getdents/getdents02.c
    156 @@ -69,21 +69,12 @@ int TST_TOTAL = 1;
    157  
    158  int exp_enos[] = { EBADF, 0 };	/* 0 terminated list of expected errnos */
    159  
    160 -#ifndef __i386__
    161 -int main(void)
    162 -{
    163 -	tst_brkm(TCONF, NULL, "this test will only run on i386");
    164 -	tst_exit();
    165 -}
    166 -#else
    167 -
    168  int main(int ac, char **av)
    169  {
    170  	int lc;
    171  	char *msg;
    172  	int rval, fd;
    173  	int count;
    174 -	const int cnum = __NR_getdents;
    175  	size_t size = 0;
    176  	char *dir_name = NULL;
    177  	struct dirent *dirp;
    178 @@ -109,25 +100,15 @@ int main(int ac, char **av)
    179  
    180  		fd = -5;
    181  
    182 -		/*
    183 -		 * here's a case where invoking the system call directly
    184 -		 * doesn't seem to work.  getdents.h has an assembly
    185 -		 * macro to do the job.
    186 -		 *
    187 -		 * equivalent to  - getdents(fd, dirp, count);
    188 -		 * if we could call getdents that way.
    189 -		 */
    190 -
    191 -		rval = GETDENTS_ASM();
    192 +		rval = getdents(fd, dirp, count);
    193  
    194  		/*
    195  		 * Hopefully we get an error due to the bad file descriptor.
    196  		 */
    197  		if (rval < 0) {
    198 -			rval *= -1;
    199 -			TEST_ERROR_LOG(rval);
    200 +			TEST_ERROR_LOG(errno);
    201  
    202 -			switch (rval) {
    203 +			switch (errno) {
    204  			case EBADF:
    205  				tst_resm(TPASS,
    206  				    "failed as expected with EBADF");
    207 @@ -170,5 +151,3 @@ void cleanup(void)
    208  
    209  	tst_rmdir();
    210  }
    211 -
    212 -#endif /* __i386__ */
    213 diff --git a/testcases/kernel/syscalls/getdents/getdents03.c b/testcases/kernel/syscalls/getdents/getdents03.c
    214 index 8582346..ffd137f 100644
    215 --- a/testcases/kernel/syscalls/getdents/getdents03.c
    216 +++ b/testcases/kernel/syscalls/getdents/getdents03.c
    217 @@ -72,21 +72,12 @@ int TST_TOTAL = 1;
    218  
    219  int exp_enos[] = { EINVAL, 0 };	/* 0 terminated list of expected errnos */
    220  
    221 -#ifndef __i386__
    222 -int main(void)
    223 -{
    224 -	tst_brkm(TCONF, NULL, "this test will only run on i386");
    225 -	tst_exit();
    226 -}
    227 -#else
    228 -
    229  int main(int ac, char **av)
    230  {
    231  	int lc;
    232  	char *msg;
    233  	int rval, fd;
    234  	int count;
    235 -	const int cnum = __NR_getdents;
    236  	size_t size = 0;
    237  	char *dir_name = NULL;
    238  	struct dirent *dirp;
    239 @@ -114,26 +105,16 @@ int main(int ac, char **av)
    240  		if ((fd = open(dir_name, O_RDONLY)) == -1)
    241  			tst_brkm(TBROK, cleanup, "open of directory failed");
    242  
    243 -		/*
    244 -		 * here's a case where invoking the system call directly
    245 -		 * doesn't seem to work.  getdents.h has an assembly
    246 -		 * macro to do the job.
    247 -		 *
    248 -		 * equivalent to  - getdents(fd, dirp, count)
    249 -		 * if we could call getdents that way.
    250 -		 */
    251 -
    252 -		rval = GETDENTS_ASM();
    253 +		rval = getdents(fd, dirp, count);
    254  
    255  		/*
    256  		 * Hopefully we get an error due to the small buffer.
    257  		 */
    258  
    259  		if (rval < 0) {
    260 -			rval *= -1;
    261 -			TEST_ERROR_LOG(rval);
    262 +			TEST_ERROR_LOG(errno);
    263  
    264 -			switch (rval) {
    265 +			switch (errno) {
    266  			case EINVAL:
    267  				tst_resm(TPASS,
    268  				    "getdents failed with EINVAL as expected");
    269 @@ -181,5 +162,3 @@ void cleanup(void)
    270  
    271  	tst_rmdir();
    272  }
    273 -
    274 -#endif /* __i386__ */
    275 diff --git a/testcases/kernel/syscalls/getdents/getdents04.c b/testcases/kernel/syscalls/getdents/getdents04.c
    276 index 5dd1634..141d3da 100644
    277 --- a/testcases/kernel/syscalls/getdents/getdents04.c
    278 +++ b/testcases/kernel/syscalls/getdents/getdents04.c
    279 @@ -73,20 +73,11 @@ int TST_TOTAL = 1;
    280  
    281  int exp_enos[] = { ENOTDIR, 0 };	/* 0 terminated list of expected errnos */
    282  
    283 -#ifndef __i386__
    284 -int main(void)
    285 -{
    286 -	tst_brkm(TCONF, NULL, "this test will only run on i386");
    287 -	tst_exit();
    288 -}
    289 -#else
    290 -
    291  int main(int ac, char **av)
    292  {
    293  	int lc;
    294  	char *msg;
    295  	int count, rval, fd;
    296 -	const int cnum = 141;
    297  	size_t size = 0;
    298  	char *dir_name = NULL;
    299  	struct dirent *dirp;
    300 @@ -131,15 +122,7 @@ int main(int ac, char **av)
    301  		if (S_ISDIR(sbuf->st_mode))
    302  			tst_brkm(TBROK, cleanup, "fd is a directory");
    303  
    304 -		/*
    305 -		 * here's a case where invoking the system call directly
    306 -		 * doesn't seem to work.  getdents.h has an assembly
    307 -		 * macro to do the job.
    308 -		 *
    309 -		 * equivalent to getdents(fd, dirp, count);
    310 -		 */
    311 -
    312 -		rval = GETDENTS_ASM();
    313 +		rval = getdents(fd, dirp, count);
    314  
    315  		/*
    316  		 * Calling with a non directory file descriptor should give
    317 @@ -147,10 +130,9 @@ int main(int ac, char **av)
    318  		 */
    319  
    320  		if (rval < 0) {
    321 -			rval *= -1;
    322 -			TEST_ERROR_LOG(rval);
    323 +			TEST_ERROR_LOG(errno);
    324  
    325 -			switch (rval) {
    326 +			switch (errno) {
    327  			case ENOTDIR:
    328  				tst_resm(TPASS,
    329  				    "getdents failed as expected with ENOTDIR");
    330 @@ -198,5 +180,3 @@ void cleanup(void)
    331  
    332  	tst_rmdir();
    333  }
    334 -
    335 -#endif /* __i386__ */
    336 -- 
    337 1.7.8.4
    338 
    339