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