Wednesday, 22 February 2017

Test cases of dup3() for radix tree__alloc_fd

I have written dup3() test case.
I am going to run this test case for the close_on_exec patch.
Also, I have written one program (child_process.c) which will run on exec and try to open the file using fdopen().

dup3() test case is given below,

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * This is dup3() functionality testcase. 
 * The dup3() is duplicate a file descriptor to a given number, 
 * with flags.
 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>

extern char **environ;

#define WRONG_FLAG -1

int dup3_basic_tests () {

 int oldfd, newfd;
 int ret;

 oldfd = open("/tmp/file1",O_CREAT | O_RDWR, 0644);
 if (oldfd < 0) {
  printf("open() error \n");
  return -1;
 }
 ret = fcntl(oldfd, F_GETFD);
 if (ret != FD_CLOEXEC)
  printf("test 1 : pass\n");
 else
  printf("test 1 : fail\n");

 ret = dup3(oldfd, newfd, O_CLOEXEC);
 if (ret == -1) {
  printf("dup3() error \n");
  return -1;
 }

 ret = fcntl(newfd, F_GETFD);   /* Read the file descriptor flags */

 if (ret == FD_CLOEXEC)
  printf("test 2 : pass\n");
 else
  printf("test 2 : fail\n");

 close(newfd);

 ret = dup3(oldfd, newfd, 0);
 if (ret == -1) {
  printf("dup3() error \n");
  return -1;
 }

 ret = fcntl(newfd, F_GETFD);

 if (ret != FD_CLOEXEC)
  printf("test 3 : pass\n");
 else
  printf("test 3 : fail\n");

 close(newfd);

 ret = dup3(oldfd, newfd, WRONG_FLAG);
 if (ret == -1)
  printf("test 4 : pass \n");
 else
  printf("test 4 : fail \n");

 close(oldfd);
 unlink("/tmp/file1");
 return 0;
}

int dup3_loop() {
 int i,ret;
 int oldfd, newfd;

 oldfd = open("/tmp/file2",O_CREAT | O_RDWR, 0644);
 if (oldfd < 0) {
  printf("open() error \n");
  return -1;
 }

 for (i = 3; i < 100; i++) {
  ret = dup3(oldfd, i, O_CLOEXEC);
  if (ret < 0) {
   printf("dup3_loop : dup3() error\n");
   return -1;
  }  
 }
 for (i = 3; i < 100; i++) {
  ret = fcntl(i, F_GETFD);
  if (ret < 0) {
   printf("dup3_loop : fcntl() error\n");
   return -1;
  }
  if (ret == FD_CLOEXEC)
   printf("dup3_loop() : pass.%d\n",i);
  else
   printf("dup3_loop() : fail.%d\n",i);

  close(i);
 }

 unlink("/tmp/file2");
}

void fork_exec() {
 int fd,new_fd = 4;
 int pid,ret;
 char fd_buf[10];
 char *argv[3] = {"child_process",fd_buf, NULL};

 fd = open("/tmp/file3",O_CREAT | O_RDWR, 0644);
 if (fd < 0){
  printf("fork_exec : open failed\n");
  exit(-1); 
 }

 ret = dup3(fd, new_fd, O_CLOEXEC);
 printf("parent process new_fd %d\n", new_fd);
 if (ret < 0){
  printf("dup3 : dup3 failed\n");
  exit(-1);
 }

 pid = fork();

 if (pid == 0) {
  sprintf(fd_buf,"%d",new_fd);
  ret = execvp("./child_process", argv);
  if (ret < 0) {
   printf("execv() failed...\n");
   exit(-1);
  }
 }
}

int main() {
 int ret;
 ret = dup3_basic_tests();
 if (ret == -1)
  return -1;
 ret = dup3_loop();
 if (ret == -1)
  return -1;
 fork_exec();
 return 0; 
}



Program for child_process.c which will run on exec,
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[]) {

 int fd,ret;
 FILE *file;

 if (argc < 2) {
  printf("Usage : %s fd\n",argv[0]);
  return -1;
 }

 fd = atoi(argv[1]);
 printf("child process fd %d\n", fd); 
 file = fdopen(fd, "r+");
 if (file == NULL)
  printf("fork-exec : test pass\n");
 else
  printf("fork-exec : test fail\n");
 
 return 0;
}

Tuesday, 31 January 2017

Test cases of dup2() for radix tree__alloc_fd

I have written a test case of dup2()
This is dup2() functionality test case. The dup2() makes newfd be the copy of oldfd, closing newfd first if necessary.
This test case covers below scenarios
  * Provide invalid file descriptor to dup2()
  * Fill up all file descriptor table and try to duplicate a file descriptor using dup2().
  * Using dup2() duplicate both file descriptor return by the pipe.
  * Check inode number after passing newfd and oldfd to fstat(). inode number should be same.

Upon successful execution this program will return zero value, otherwise, it will return -1.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int maxfd;

int dup2_misc_tc()
{
 int *fd, i, maxfd;
 int ret, goodfd;

goodfd = open("test/file1", O_CREAT | O_RDWR, 0644);
 
 if(goodfd == -1)
 {
  printf("dup2_misc_tc() : dup2 failed...\n");
  return -1;
  }
 ret = dup2(-1, goodfd);
 if(ret == -1)
 {
  printf("dup2_misc_tc1 : Pass \n");
 }
 else
 {
  printf("dup2_misc_tc1: fail \n");
 }
 ret = dup2(goodfd, -1);
 if(ret == -1)
 {
  printf("dup2_misc_tc1 : Pass \n");
 }
 else
 {
  printf("dup2_misc_tc1: fail \n");
 }

close(goodfd);
 unlink("test/file1");

return 0;
}

int max_fd_dup2()
{
 int *fd, i;
 int ret;
 char buf[15];
 maxfd = getdtablesize();
 
 fd = malloc(maxfd * sizeof(int));
 printf("maxfd = %d\n",maxfd);

for(i = 0; i < (maxfd-3); i++)
 {
  sprintf(buf, "test/myfile%d", i);
  fd[i] = open(buf, O_CREAT | O_RDWR, 0644);
  if (fd[i] == -1)
  {
   printf("max_fd_dup2() :: open() failed...\n");
   return -1;
  }
 }
 printf("here ***************\n");
 ret = dup2(10,24);
 if(ret == -1)
  printf("max_fd_dup2: tc: Fail\n");
 else
  printf("max_fd_dup2: tc: Pass\n");
 
 ret = dup2(10,maxfd);
 if(ret == -1)
  printf("max_fd_dup2: tc: Pass\n");
 else
  printf("max_fd_dup2: tc: Fail\n");

return 0;
 
}

int pipe_dup2_tc()
{
 int fd[2];
 int ret;
 ret = pipe(fd);
 if(ret == -1)
 {
  printf("pipe_dup2_tc : Pipe Failed\n");
  return -1;
 }
 ret = dup2(fd[0],5);
 
 if(ret == -1)
 
  printf("pipe_dup2_tc : fail\n");
 else
  printf("pipe_dup2_tc: pass1\n");

ret = dup2(fd[1],6); 
 if(ret == -1)
 
  printf("pipe_dup2_tc : fail\n");
 else
  printf("pipe_dup2_tc: pass2\n");
 
 close(fd[0]);
 close(fd[1]);
 return 0;
}

int dup2_ino_tc()
{
        struct stat buf1, buf2;
        char buf[20];
        int ret, oldfd, newfd, fd_fd;

oldfd = open("test/file11", O_CREAT | O_RDWR, 0644);
        if(oldfd == -1)
        {
                printf("dup_misc_tc() : open() failed...\n");
                return -1;
        }
 
        newfd = open("test/file12", O_CREAT | O_RDWR, 0644);
        if(newfd == -1)
        {
                printf("dup_misc_tc() : open() failed...\n");
                return -1;
        }

ret = dup2(oldfd,newfd);
        if (ret == -1)
        {
                printf("dup2_ino_tc : fail\n");
        }
        else
        {
                printf("dup2_ino_tc : pass\n");
        }

ret = fstat(oldfd, &buf1); /* get the file status */
        if(ret == -1)
        {
                printf("dup2_ino_tc() : fstat() failed...\n");
                return -1;
        }

ret = fstat(newfd, &buf2);
        if(ret == -1)
        {
                printf("dup2_ino_tc() : fstat() failed...\n");
                return -1;
        }

printf("buf1.st_ino = %lu\n",buf1.st_ino);
        printf("buf2.st_ino = %lu\n",buf2.st_ino);
        if(buf1.st_ino == buf2.st_ino)
                printf("dup2_ino_tc : pass\n");
        else
                printf("dup2_ino_tc : fail\n");
        close(oldfd);
        close(newfd);
        unlink("test/file1");
 
        return 0;
}

int close_fd(int count) 
{
 int i;
 for(i = 3; i < count; i++)
 {
  close(i);
 }
}

void unlink_files(int count)
{
 char buf[15];
 int i;

for(i = 0; i < count; i++)
 {
  sprintf(buf,"test/myfile%d",i);
  unlink(buf);
 }
}

int main(int argc, char **argv)
{
 int err = 0;
 char *name;
 int goodfd;
 if(argc < 2)
 {
  printf("usage: %s <tcNUM> \n", argv[0]);
  printf("Provide oprion to program as tc1, tc2, tc3, tc4\n");
  return -1;
 }
 name = argv[1];
 
 if(strcmp(name, "tc1") == 0)
 {
  err = dup2_misc_tc();
  if(err == -1)
  {
   return -1;
  }
 }
 else if(strcmp(name, "tc2") == 0)
 {
  max_fd_dup2();
  close_fd(maxfd-3);
  unlink_files(maxfd);
 }
 
 else if(strcmp(name, "tc3") == 0)
 {
  pipe_dup2_tc(); 
 }
 
 else if(strcmp(name, "tc4") == 0)
 {
  dup2_ino_tc();
 }

return 0;
}

Test cases of dup() for radix tree__alloc_fd

I have written the test case for dup( ).
This is dup( ) functionality test case. The dup( ) use for duplicate the file descriptor.
This test case covers below different scenarios:
* Duplicate file descriptor five times one by one.
* Fill up all file descriptor table and try to duplicate a file descriptor. dup( ) should not be succeeded.
* Give invalid file descriptor to the dup( ). dup( ) should be failed.
* Check inode number after passing newfd and oldfd to fstat( ). inode number should be same.
 Upon successful execution this program will return zero value, otherwise, it will return -1.



  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int maxfd;

int dup_fd(int count)
{
 int fd[count],i;
 char buf[15];

for(i = 0; i < count; i++)
 {
 sprintf(buf, test/myfile%d, i);
 fd[i] = open(buf, O_CREAT | O_RDWR, 0644); 
 printf(open: %d\n, fd[i]);
 if(fd[i] == -1)
 {
 printf(open() failed\n);
 return -1;
 }
 fd [i+1] = dup(i);
 if (fd [i+1] == -1)
 {
 printf(dup() failed\n);
 return -1;
 }
 printf(dup: %d\n, fd [i+1]);
 }
 
 return 0;
}
void close_fd(int count)
{
 int i;
 for (i = 3; i < count; i++)
 {
 close(i);
 }
}

void unlink_files(int count)
{
 char buf[15];
 int i;

for(i = 0; i < count; i++)
 {
 sprintf(buf,test/myfile%d,i);
 unlink(buf);
 }
}

int max_fd_dup() 
{
 int *fd, i;
 int ret;
 char buf[15];
 maxfd = getdtablesize(); /* get descriptor table size */

 fd = malloc(maxfd * sizeof(int)); /* allocate the memory */

 printf(maxfd = %d\n,maxfd);

 for (i = 0; i < (maxfd-3); i++)
 {
 sprintf(buf, test/myfile%d, i);
 fd[i] = open(buf, O_CREAT | O_RDWR, 0644); 
 if (fd[i] == -1)
 {
 printf(max_fd_dup() :: open() failed\n);
 return -1;
 }
 }
 printf(here *****************\n);
 
 ret = dup(10); /* duplicate the file descriptor */
 
 if(ret == -1)
 printf(max_fd_dup: tc : pass\n);
 else
 printf(max_fd_dup: tc : fail\n);

return 0;
}
int dup_misc_tc()
{
 int *fd, i, maxfd;
 struct stat buf1, buf2;
 char buf[20];
 int ret, oldfd, newfd;

 ret = dup(10);
  if (ret == -1)
  {
  printf(dup_misc_tc1 : pass\n);
  }
  else
  {
  printf(dup_misc_tc1 : fail\n);
  }

 ret = dup(-1);

 if (ret == -1)
  {
  printf(dup_misc_tc2 : pass\n);
  }
 else
  {
  printf(dup_misc_tc2 : fail\n);
  }

 oldfd = open(test/file1, O_CREAT | O_RDWR, 0644);
 if(oldfd == -1)
 {
  printf(dup_misc_tc() : open() failed\n);
  return -1;
 }
 
 newfd = dup(oldfd);
 if(newfd == -1)
 {
  printf(dup_misc_tc() : dup() failed\n);
  return -1;
 }

 ret = fstat(oldfd, &buf1); /* get the file status */
 if(ret == -1)
 {
  printf(dup_misc_tc() : fstat() failed\n);
  return -1;
 }
 ret = fstat(newfd, &buf2);
 if(ret == -1)
 {
  printf(dup_misc_tc() : fstat() failed\n);
  return -1;
 }

 printf(buf1.st_ino = %d\n,buf1.st_ino);
 printf(buf2.st_ino = %d\n,buf2.st_ino);
 if(buf1.st_ino == buf2.st_ino)
  printf(dup_misc_tc3 : pass\n);
 else
  printf(dup_misc_tc3 : fail\n);
 close(oldfd);
 close(newfd);
 unlink(test/file1);
 return 0;
}

int main(int argc, char **argv)
{
 int err = 0;
 char *name;

if(argc < 2)
 {
 printf(usage: %s <tcNum> \n, argv[0]);
 printf(provide options to program as tc1, tc2, tc3 etc\n);
 return -1;
 }
 name = argv[1];

if(strcmp(name, tc1) == 0)
 {

err = dup_fd(5);
 if (err == -1)
 {
 return -1;
 }
 close_fd(10);
 unlink_files(5);
 }
 else if(strcmp(name, tc2) == 0)
 {
  max_fd_dup();
  close_fd(maxfd-3);
  unlink_files(maxfd);
 }
 else if(strcmp(name, tc3) == 0)
 {
  dup_misc_tc();
 }
 else
  printf(Invalid option \n);

return 0;
}

Threaded test case for radix tree __alloc_fd

The purpose of this test cases is to stress the locking inside the kernel.

All threads share a common file descriptor table. As each thread opens and closes its file descriptors, it must ensure that other threads do not interfere. So if we have many threads running, simultaneously opening and closing file descriptors, we’re trying to provoke a crash, or a corruption, or some other bad behavior by the kernel.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>

#define NUM_THREADS 12
#define BUF_SIZE 1024

void *fd_task(void *arg)
{
 int fd, err = 0;
 int ret;
 char buf[BUF_SIZE];

 fd = open(/etc/passwd,O_RDONLY);
 if(fd == -1) {
  printf(open failed\n);
 }

 ret = read(fd, buf, 1024);
 if(ret < 0) {
  printf(read failed\n);
 }
 close(fd);
}

int main(int argc, char *argv[]) {
 int i, err;
 pthread_t thread[NUM_THREADS];

/* Create threads*/
 for (i = 0; i < NUM_THREADS; ++i) {
 if ((err = pthread_create(&thread[i], NULL, fd_task, NULL)))
 {
  printf(Error : pthread_create()\n);
  goto out;
 }
 }

/* block until all threads complete */
 for (i = 0; i < NUM_THREADS; ++i)
 {
  pthread_join(thread[i], NULL);
 }
out:
 return err;
}

Performance test case in radix tree __alloc_fd

This is the performance test case. It is used to check the time taken to do several allocation and deallocation of the file descriptors.
This test performs below steps: 
 * Open 1000 file
 * Close 20 files
 * Open 20 files again.
 * Repeat step 2
Upon successful execution, this program will return zero and print the time taken by the program on the terminal.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{

 int fd[1000], nfd[20];
 int i, j, rfd[20], cnt = 1000;
 char buf[15];
 int err = 0;
 int opt, nloop = 100000;
 clock_t start, end;
 double time_taken;
 unsigned int seed = time(NULL);
 
 while ((opt = getopt(argc, argv, s:l:)) != -1)
 {
 switch (opt) {
 case s:
 seed = atoi(optarg);
 printf(seed = %d\n,seed);
 break;
 case l:
 nloop = atoi(optarg);
 printf(nloop = %d\n,nloop);
 break;
 }
 }
 
 for(i = 0; i < 1000; i++)
 {
  sprintf(buf, test/myfile%d, i);
  fd[i] = open(buf, O_CREAT | O_RDWR, 0644);
 
 if(fd[i] == -1)
 {
  err = errno;
  cnt = i;
  goto out;
 }
 }
 
 
 srand(seed);
 start = clock(); /* start time */
 for(i = 0; i < nloop; i++)
 {
 /* Close any 20 files randomly */
 for(j = 0; j < 20; j++)
 {
  rfd[j] = rand() % 1000+3;
  err = close(rfd[j]);
 if(err == -1)
 {
 if(errno == EBADF)
  j  ;
 else
  abort();
 }
 }

/* Open 20 files which are closed by above loop */
 for(j = 0; j < 20; j++)
 {
  sprintf(buf, test/myfile%d,rfd[j]);
  nfd[j] = open(buf, O_CREAT | O_RDWR, 0644);
 if(nfd[j] < 0)
 {
  err = errno;
  goto out;
 }
 }
 }
 
 end = clock(); /* end time */
 time_taken = ((double) (end  start)) / CLOCKS_PER_SEC;
 printf(This program took %f seconds to execute\n,time_taken);
 printf(Time taken by per file descriptor opened-closed : %.2f microsecond\n,
 (time_taken/(nloop*20))*1000000);
out:
 for(i = 0; i < cnt; i++)
 {
  sprintf(buf, test/myfile%d,i);
  unlink(buf);
 }
 return err;
}


I have taken below reading for above test case ,
Performance numbers are as below :



 



 

About me...

Hello,
My name is Sandhya Bankar, recently started working with The Linux Foundation as Outreachy intern.
I have completed my Master of Engineering in Computers from G.H.Raisoni, Pune, India, and Bachelor of Engineering in Electronics from P.E.S college of Engineering, Aurangabad India. As I come from two different streams, so I like to enjoy hardware as well as software parts. I am interested in learning new things.
I love the Embedded system, Operating system, wireless sensor networking. My initial preference is C, C++, and Python language. I am passionate about open source and I always like to explore Linux kernel.
Other than technical studies I love reading book’s and doing Meditation. I also like to spend time for outdoor games.