2 * open_by_handle.c - attempt to create a file handle and open it
3 * with open_by_handle_at() syscall
5 * Copyright (C) 2017 CTERA Networks. All Rights Reserved.
6 * Author: Amir Goldstein <amir73il@gmail.com>
11 * Copyright (C) 2010 Red Hat, Inc. All Rights reserved.
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 usage: open_by_handle [-cludm] <test_dir> [num_files]
34 1. Create test set of N files and try to get their NFS handles:
36 open_by_handle -c <test_dir> [N]
38 This is used by new helper _require_exportfs() to check
39 if filesystem supports exportfs
41 2. Get file handles for existing test set, drop caches and try to
42 open all files by handle:
44 open_by_handle <test_dir> [N]
46 3. Get file handles for existing test set, unlink all test files,
47 drop caches, try to open all files by handle and expect ESTALE:
49 open_by_handle -d <test_dir> [N]
51 4. Get file handles for existing test set, rename all test files,
52 drop caches, try to open all files by handle (should work):
54 open_by_handle -m <test_dir> [N]
56 5. Get file handles for existing test set, hardlink all test files,
57 then unlink the original files, drop caches and try to open all
58 files by handle (should work):
60 open_by_handle -l <test_dir> [N]
61 open_by_handle -u <test_dir> [N]
63 This test is done with 2 invocations of the program, first to
64 hardlink (-l) and then to unlink the originals (-u), because
65 we would like to be able to perform the hardlinks on overlay
66 lower layer and unlink on upper layer.
68 NOTE that open_by_handle -u doesn't check if the files are
69 hardlinked, it just assumes that they are. If they are not
70 then the test will fail, because file handles would be stale.
79 #include <sys/types.h>
81 #include <linux/limits.h>
86 struct file_handle fh;
87 unsigned char fid[MAX_HANDLE_SZ];
92 fprintf(stderr, "usage: open_by_handle [-cludm] <test_dir> [num_files]\n");
93 fprintf(stderr, "\n");
94 fprintf(stderr, "open_by_handle -c <test_dir> [N] - create N test files under test_dir, try to get file handles and exit\n");
95 fprintf(stderr, "open_by_handle <test_dir> [N] - get file handles of test files, drop caches and try to open by handle\n");
96 fprintf(stderr, "open_by_handle -l <test_dir> [N] - create hardlinks to test files, drop caches and try to open by handle\n");
97 fprintf(stderr, "open_by_handle -u <test_dir> [N] - unlink (hardlinked) test files, drop caches and try to open by handle\n");
98 fprintf(stderr, "open_by_handle -d <test_dir> [N] - unlink test files and hardlinks, drop caches and try to open by handle\n");
99 fprintf(stderr, "open_by_handle -m <test_dir> [N] - rename test files, drop caches and try to open by handle\n");
103 int main(int argc, char **argv)
109 char fname[PATH_MAX];
110 char fname2[PATH_MAX];
112 int mount_fd, mount_id;
114 int create = 0, delete = 0, nlink = 1, move = 0;
116 if (argc < 2 || argc > 4)
119 while ((c = getopt(argc, argv, "cludm")) != -1) {
139 fprintf(stderr, "illegal option '%s'\n", argv[optind]);
144 if (optind == argc || optind > 2)
146 test_dir = argv[optind++];
148 numfiles = atoi(argv[optind]);
149 if (!numfiles || numfiles > MAXFILES) {
150 fprintf(stderr, "illegal value '%s' for num_files\n", argv[optind]);
154 mount_fd = open(test_dir, O_RDONLY|O_DIRECTORY);
161 * Create the test files and remove leftover hardlinks from previous run
163 for (i=0; create && i < numfiles; i++) {
164 sprintf(fname, "%s/file%06d", test_dir, i);
165 sprintf(fname2, "%s/link%06d", test_dir, i);
166 fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
168 strcat(fname, ": open");
173 /* blow up leftovers hardlinks if they exist */
174 ret = unlink(fname2);
175 if (ret < 0 && errno != ENOENT) {
176 strcat(fname2, ": unlink");
182 /* sync to get the new inodes to hit the disk */
185 /* create the handles */
186 for (i=0; i < numfiles; i++) {
187 sprintf(fname, "%s/file%06d", test_dir, i);
188 handle[i].fh.handle_bytes = MAX_HANDLE_SZ;
189 ret = name_to_handle_at(AT_FDCWD, fname, &handle[i].fh, &mount_id, 0);
191 strcat(fname, ": name_to_handle");
197 /* after creating test set only check that fs supports exportfs */
201 /* hardlink the files */
202 for (i=0; nlink > 1 && i < numfiles; i++) {
203 sprintf(fname, "%s/file%06d", test_dir, i);
204 sprintf(fname2, "%s/link%06d", test_dir, i);
205 ret = link(fname, fname2);
207 strcat(fname2, ": link");
213 /* rename the files */
214 for (i=0; move && i < numfiles; i++) {
215 sprintf(fname, "%s/file%06d", test_dir, i);
216 sprintf(fname2, "%s/link%06d", test_dir, i);
217 ret = rename(fname, fname2);
219 strcat(fname2, ": rename");
225 /* unlink the files */
226 for (i=0; delete && i < numfiles; i++) {
227 sprintf(fname, "%s/file%06d", test_dir, i);
228 sprintf(fname2, "%s/link%06d", test_dir, i);
231 strcat(fname, ": unlink");
235 /* with -d flag, delete the hardlink if it exists */
237 ret = unlink(fname2);
238 if (ret < 0 && errno != ENOENT) {
239 strcat(fname2, ": unlink");
245 /* sync to get log forced for unlink transactions to hit the disk */
248 /* sync once more FTW */
252 * now drop the caches so that unlinked inodes are reclaimed and
253 * buftarg page cache is emptied so that the inode cluster has to be
254 * fetched from disk again for the open_by_handle() call.
256 ret = system("echo 3 > /proc/sys/vm/drop_caches");
258 perror("drop_caches");
263 * now try to open the files by the stored handles. Expecting ESTALE
264 * if all files and their hardlinks have been unlinked.
266 for (i=0; i < numfiles; i++) {
268 fd = open_by_handle_at(mount_fd, &handle[i].fh, O_RDWR);
269 if (nlink && fd >= 0) {
272 } else if (!nlink && fd < 0 && (errno == ENOENT || errno == ESTALE)) {
275 sprintf(fname, "%s/file%06d", test_dir, i);
277 printf("open_by_handle(%s) opened an unlinked file!\n", fname);
280 printf("open_by_handle(%s) returned %d incorrectly on %s file!\n",
282 nlink ? "a linked" : "an unlinked");