| /* | 
 |  *  stale_handle.c - attempt to create a stale handle and open it | 
 |  * | 
 |  *  Copyright (C) 2010 Red Hat, Inc. All Rights reserved. | 
 |  * | 
 |  *  This program is free software; you can redistribute it and/or modify | 
 |  *  it under the terms of the GNU General Public License as published by | 
 |  *  the Free Software Foundation; either version 2 of the License, or | 
 |  *  (at your option) any later version. | 
 |  * | 
 |  *  This program is distributed in the hope that it will be useful, | 
 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |  *  GNU General Public License for more details. | 
 |  * | 
 |  *  You should have received a copy of the GNU General Public License | 
 |  *  along with this program; if not, write to the Free Software | 
 |  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. | 
 |  */ | 
 |  | 
 | #define TEST_UTIME | 
 |  | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <fcntl.h> | 
 | #include <unistd.h> | 
 | #include <sys/stat.h> | 
 | #include <sys/types.h> | 
 | #include <errno.h> | 
 | #include <xfs/xfs.h> | 
 | #include <xfs/handle.h> | 
 |  | 
 | #define NUMFILES 1024 | 
 | int main(int argc, char **argv) | 
 | { | 
 | 	int	i; | 
 | 	int	fd; | 
 | 	int	ret; | 
 | 	int	failed = 0; | 
 | 	char	fname[MAXPATHLEN]; | 
 | 	char	*test_dir; | 
 | 	void	*handle[NUMFILES]; | 
 | 	size_t	hlen[NUMFILES]; | 
 | 	char	fshandle[256]; | 
 | 	size_t	fshlen; | 
 | 	struct stat st; | 
 |  | 
 |  | 
 | 	if (argc != 2) { | 
 | 		fprintf(stderr, "usage: stale_handle test_dir\n"); | 
 | 		return EXIT_FAILURE; | 
 | 	} | 
 |  | 
 | 	test_dir = argv[1]; | 
 | 	if (stat(test_dir, &st) != 0) { | 
 | 		perror("stat"); | 
 | 		return EXIT_FAILURE; | 
 | 	} | 
 |  | 
 | 	ret = path_to_fshandle(test_dir, (void **)fshandle, &fshlen); | 
 | 	if (ret < 0) { | 
 | 		perror("path_to_fshandle"); | 
 | 		return EXIT_FAILURE; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * create a large number of files to force allocation of new inode | 
 | 	 * chunks on disk. | 
 | 	 */ | 
 | 	for (i=0; i < NUMFILES; i++) { | 
 | 		sprintf(fname, "%s/file%06d", test_dir, i); | 
 | 		fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644); | 
 | 		if (fd < 0) { | 
 | 			printf("Warning (%s,%d), open(%s) failed.\n", __FILE__, __LINE__, fname); | 
 | 			perror(fname); | 
 | 			return EXIT_FAILURE; | 
 | 		} | 
 | 		close(fd); | 
 | 	} | 
 |  | 
 | 	/* sync to get the new inodes to hit the disk */ | 
 | 	sync(); | 
 |  | 
 | 	/* create the handles */ | 
 | 	for (i=0; i < NUMFILES; i++) { | 
 | 		sprintf(fname, "%s/file%06d", test_dir, i); | 
 | 		ret = path_to_handle(fname, &handle[i], &hlen[i]); | 
 | 		if (ret < 0) { | 
 | 			perror("path_to_handle"); | 
 | 			return EXIT_FAILURE; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* unlink the files */ | 
 | 	for (i=0; i < NUMFILES; i++) { | 
 | 		sprintf(fname, "%s/file%06d", test_dir, i); | 
 | 		ret = unlink(fname); | 
 | 		if (ret < 0) { | 
 | 			perror("unlink"); | 
 | 			return EXIT_FAILURE; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* sync to get log forced for unlink transactions to hit the disk */ | 
 | 	sync(); | 
 |  | 
 | 	/* sync once more FTW */ | 
 | 	sync(); | 
 |  | 
 | 	/* | 
 | 	 * now drop the caches so that unlinked inodes are reclaimed and | 
 | 	 * buftarg page cache is emptied so that the inode cluster has to be | 
 | 	 * fetched from disk again for the open_by_handle() call. | 
 | 	 */ | 
 | 	system("echo 3 > /proc/sys/vm/drop_caches"); | 
 |  | 
 | 	/* | 
 | 	 * now try to open the files by the stored handles. Expecting ENOENT | 
 | 	 * for all of them. | 
 | 	 */ | 
 | 	for (i=0; i < NUMFILES; i++) { | 
 | 		errno = 0; | 
 | 		fd = open_by_handle(handle[i], hlen[i], O_RDWR); | 
 | 		if (fd < 0 && (errno == ENOENT || errno == ESTALE)) { | 
 | 			free_handle(handle[i], hlen[i]); | 
 | 			continue; | 
 | 		} | 
 | 		if (fd >= 0) { | 
 | 			printf("open_by_handle(%d) opened an unlinked file!\n", i); | 
 | 			close(fd); | 
 | 		} else | 
 | 			printf("open_by_handle(%d) returned %d incorrectly on an unlinked file!\n", i, errno); | 
 | 		free_handle(handle[i], hlen[i]); | 
 | 		failed++; | 
 | 	} | 
 | 	if (failed) | 
 | 		return EXIT_FAILURE; | 
 | 	return EXIT_SUCCESS; | 
 | } |