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