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