Whamcloud - gitweb
LU-4018 tests: improve racer file_create workload
[fs/lustre-release.git] / lustre / tests / check_fhandle_syscalls.c
1 /* GPL HEADER START
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 only,
7  * as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License version 2 for more details (a copy is included
13  * in the LICENSE file that accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License
16  * version 2 along with this program; If not, see
17  * http://www.gnu.org/licenses/gpl-2.0.html
18  *
19  * GPL HEADER END
20  */
21
22 /*
23  * Copyright (C) 2013, DataDirect Networks, Inc.
24  * Author: Swapnil Pimpale <spimpale@ddn.com>
25  */
26
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE
29 #endif
30
31 #include <stdio.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <string.h>
38 #include <mntent.h>
39 #include <linux/unistd.h>
40 #include <sys/stat.h>
41 #include <sys/syscall.h>
42
43 #include <libcfs/libcfs.h>
44 #include <lustre/lustre_user.h>
45
46 #define MAX_HANDLE_SZ 128
47
48 #if !defined(HAVE_FHANDLE_GLIBC_SUPPORT) && defined(HAVE_FHANDLE_SYSCALLS)
49 /* Because the kernel supports this functions doesn't mean that glibc does.
50  * Just in case we define what we need */
51 struct file_handle {
52         __u32 handle_bytes;
53         int handle_type;
54         /* file identifier */
55         unsigned char f_handle[0];
56 };
57
58 #if defined(_ASM_X86_UNISTD_64_H)
59
60 #ifndef __NR_name_to_handle_at
61 #define __NR_name_to_handle_at 303
62 #endif
63
64 #ifndef __NR_open_by_handle_at
65 #define __NR_open_by_handle_at 304
66 #endif
67
68 #elif defined(_ASM_X86_UNISTD_32_H)
69
70 #ifndef __NR_name_to_handle_at
71 #define __NR_name_to_handle_at 341
72 #endif
73
74 #ifndef __NR_open_by_handle_at
75 #define __NR_open_by_handle_at 342
76 #endif
77
78 #else
79
80 #ifndef __NR_name_to_handle_at
81 #define __NR_name_to_handle_at 264
82 #endif
83
84 #ifndef __NR_open_by_handle_at
85 #define __NR_open_by_handle_at 265
86 #endif
87
88
89 #endif
90
91 static inline int
92 name_to_handle_at(int mnt_fd, const char *filename, struct file_handle *fh,
93                   int *mnt_id, int flags)
94 {
95         return syscall(__NR_name_to_handle_at, mnt_fd, filename, fh,
96                        &mnt_id, flags);
97 }
98
99 static inline int
100 open_by_handle_at(int mnt_fd, struct file_handle *fh, int mode)
101 {
102         return syscall(__NR_open_by_handle_at, mnt_fd, fh, mode);
103 }
104 #endif
105
106 void usage(char *prog)
107 {
108         fprintf(stderr, "usage: %s <filepath>\n",
109                 prog);
110         fprintf(stderr, "the absolute path of a test file on a "
111                 "lustre file system is needed.\n");
112         exit(1);
113 }
114
115 int main(int argc, char **argv)
116 {
117 #ifdef HAVE_FHANDLE_SYSCALLS
118         char *filename, *file, *mount_point = NULL, *readbuf = NULL;
119         int ret, rc = -EINVAL, mnt_id, mnt_fd, fd1, fd2, i, len, offset;
120         struct file_handle *fh = NULL;
121         int file_size, mtime, ctime;
122         struct lu_fid *parent, *fid;
123         struct mntent *ent;
124         struct stat st;
125         __ino_t inode;
126         FILE *mntpt;
127
128         if (argc != 2)
129                 usage(argv[0]);
130
131         file = argv[1];
132         if (file[0] != '/') {
133                 fprintf(stderr, "Need the absolete path of the file\n");
134                 goto out;
135         }
136
137         fd1 = open(file, O_RDONLY);
138         if (fd1 < 0) {
139                 fprintf(stderr, "open file %s error: %s\n",
140                         file, strerror(errno));
141                 rc = errno;
142                 goto out;
143         }
144
145         /* Get file stats using fd1 from traditional open */
146         bzero(&st, sizeof(struct stat));
147         rc = fstat(fd1, &st);
148         if (rc < 0) {
149                 fprintf(stderr, "fstat(%s) error: %s\n", file,
150                         strerror(errno));
151                 rc = errno;
152                 goto out_fd1;
153         }
154
155         inode = st.st_ino;
156         mtime = st.st_mtime;
157         ctime = st.st_ctime;
158         file_size = st.st_size;
159
160         /* Now for the setup to use fhandles */
161         mntpt = setmntent("/etc/mtab", "r");
162         if (mntpt == NULL) {
163                 fprintf(stderr, "setmntent error: %s\n",
164                         strerror(errno));
165                 rc = errno;
166                 goto out_fd1;
167         }
168
169         while (NULL != (ent = getmntent(mntpt))) {
170                 if ((strncmp(file, ent->mnt_dir, strlen(ent->mnt_dir)) == 0) &&
171                     (strcmp(ent->mnt_type, "lustre") == 0)) {
172                         mount_point = ent->mnt_dir;
173                         break;
174                 }
175         }
176         endmntent(mntpt);
177
178         if (mount_point == NULL) {
179                 fprintf(stderr, "file is not located on a lustre file "
180                         "system?\n");
181                 goto out_fd1;
182         }
183
184         filename = rindex(file, '/') + 1;
185
186         /* Open mount point directory */
187         mnt_fd = open(mount_point, O_DIRECTORY);
188         if (mnt_fd < 0) {
189                 fprintf(stderr, "open(%s) error: %s\n)", mount_point,
190                         strerror(errno));
191                 rc = errno;
192                 goto out_fd1;
193         }
194
195         /* Allocate memory for file handle */
196         fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
197         if (!fh) {
198                 fprintf(stderr, "malloc(%d) error: %s\n", MAX_HANDLE_SZ,
199                         strerror(errno));
200                 rc = errno;
201                 goto out_mnt_fd;
202         }
203         fh->handle_bytes = MAX_HANDLE_SZ;
204
205         /* Convert name to handle */
206         ret = name_to_handle_at(mnt_fd, filename, fh, &mnt_id,
207                                 AT_SYMLINK_FOLLOW);
208         if (ret) {
209                 fprintf(stderr, "name_by_handle_at(%s) error: %s\n", filename,
210                         strerror(errno));
211                 rc = errno;
212                 goto out_f_handle;
213         }
214
215         /* Print out the contents of the file handle */
216         fprintf(stdout, "fh_bytes: %u\nfh_type: %d\nfh_data: ",
217                 fh->handle_bytes, fh->handle_type);
218         for (i = 0; i < fh->handle_bytes; i++)
219                 fprintf(stdout, "%02x ", fh->f_handle[i]);
220         fprintf(stdout, "\n");
221
222         /* Lustre stores both the parents FID and the file FID
223          * in the f_handle. */
224         parent = (struct lu_fid *)(fh->f_handle + 16);
225         fid = (struct lu_fid *)fh->f_handle;
226         fprintf(stdout, "file's parent FID is "DFID"\n", PFID(parent));
227         fprintf(stdout, "file FID is "DFID"\n", PFID(fid));
228
229         /* Open the file handle */
230         fd2 = open_by_handle_at(mnt_fd, fh, O_RDONLY);
231         if (fd2 < 0) {
232                 fprintf(stderr, "open_by_handle_at(%s) error: %s\n", filename,
233                         strerror(errno));
234                 rc = errno;
235                 goto out_f_handle;
236         }
237
238         /* Get file size */
239         bzero(&st, sizeof(struct stat));
240         rc = fstat(fd2, &st);
241         if (rc < 0) {
242                 fprintf(stderr, "fstat(%s) error: %s\n", filename,
243                         strerror(errno));
244                 rc = errno;
245                 goto out_fd2;
246         }
247
248         if (ctime != st.st_ctime || file_size != st.st_size ||
249             inode != st.st_ino || mtime != st.st_mtime) {
250                 fprintf(stderr, "stat data does not match between fopen "
251                         "and fhandle case\n");
252                 goto out_fd2;
253         }
254
255         if (st.st_size) {
256                 len = st.st_blksize;
257                 readbuf = malloc(len);
258                 if (readbuf == NULL) {
259                         fprintf(stderr, "malloc(%d) error: %s\n", len,
260                                 strerror(errno));
261                         rc = errno;
262                         goto out_fd2;
263                 }
264
265                 for (offset = 0; offset < st.st_size; offset += len) {
266                         /* read from the file */
267                         rc = read(fd2, readbuf, len);
268                         if (rc < 0) {
269                                 fprintf(stderr, "read(%s) error: %s\n",
270                                         filename, strerror(errno));
271                                 rc = errno;
272                                 goto out_readbuf;
273                         }
274                 }
275         }
276
277         rc = 0;
278         fprintf(stdout, "check_fhandle_syscalls test Passed!\n");
279
280 out_readbuf:
281         if (readbuf != NULL)
282                 free(readbuf);
283 out_fd2:
284         close(fd2);
285 out_f_handle:
286         free(fh);
287 out_mnt_fd:
288         close(mnt_fd);
289 out_fd1:
290         close(fd1);
291 out:
292         return rc;
293 #else /* !HAVE_FHANDLE_SYSCALLS */
294         if (argc != 2)
295                 usage(argv[0]);
296
297         fprintf(stderr, "HAVE_FHANDLE_SYSCALLS not defined\n");
298         return 0;
299 #endif /* HAVE_FHANDLE_SYSCALLS */
300 }