mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	vfs: Add a sample program for the new mount API
Add a sample program to demonstrate fsopen/fsmount/move_mount to mount something. To make it compile on all arches, irrespective of whether or not syscall numbers are assigned, define the syscall number to -1 if it isn't to cause the kernel to return -ENOSYS. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									cf3cba4a42
								
							
						
					
					
						commit
						f1b5618e01
					
				
					 5 changed files with 153 additions and 7 deletions
				
			
		|  | @ -154,10 +154,11 @@ config SAMPLE_ANDROID_BINDERFS | |||
| 	  Builds a sample program to illustrate the use of the Android binderfs | ||||
| 	  filesystem. | ||||
| 
 | ||||
| config SAMPLE_STATX | ||||
| 	bool "Build example extended-stat using code" | ||||
| 	depends on BROKEN | ||||
| config SAMPLE_VFS | ||||
| 	bool "Build example programs that use new VFS system calls" | ||||
| 	help | ||||
| 	  Build example userspace program to use the new extended-stat syscall. | ||||
| 	  Build example userspace programs that use new VFS system calls such | ||||
| 	  as mount API and statx().  Note that this is restricted to the x86 | ||||
| 	  arch whilst it accesses system calls that aren't yet in all arches. | ||||
| 
 | ||||
| endif # SAMPLES | ||||
|  |  | |||
|  | @ -3,4 +3,4 @@ | |||
| obj-$(CONFIG_SAMPLES)	+= kobject/ kprobes/ trace_events/ livepatch/ \
 | ||||
| 			   hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
 | ||||
| 			   configfs/ connector/ v4l/ trace_printk/ \
 | ||||
| 			   vfio-mdev/ statx/ qmi/ binderfs/ | ||||
| 			   vfio-mdev/ vfs/ qmi/ binderfs/ | ||||
|  |  | |||
|  | @ -1,7 +1,10 @@ | |||
| # List of programs to build
 | ||||
| hostprogs-$(CONFIG_SAMPLE_STATX) := test-statx | ||||
| hostprogs-$(CONFIG_SAMPLE_VFS) := \
 | ||||
| 	test-fsmount \
 | ||||
| 	test-statx | ||||
| 
 | ||||
| # Tell kbuild to always build the programs
 | ||||
| always := $(hostprogs-y) | ||||
| 
 | ||||
| HOSTCFLAGS_test-fsmount.o += -I$(objtree)/usr/include | ||||
| HOSTCFLAGS_test-statx.o += -I$(objtree)/usr/include | ||||
							
								
								
									
										133
									
								
								samples/vfs/test-fsmount.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								samples/vfs/test-fsmount.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,133 @@ | |||
| /* fd-based mount test.
 | ||||
|  * | ||||
|  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. | ||||
|  * Written by David Howells (dhowells@redhat.com) | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public Licence | ||||
|  * as published by the Free Software Foundation; either version | ||||
|  * 2 of the Licence, or (at your option) any later version. | ||||
|  */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/prctl.h> | ||||
| #include <sys/wait.h> | ||||
| #include <linux/mount.h> | ||||
| #include <linux/unistd.h> | ||||
| 
 | ||||
| #define E(x) do { if ((x) == -1) { perror(#x); exit(1); } } while(0) | ||||
| 
 | ||||
| static void check_messages(int fd) | ||||
| { | ||||
| 	char buf[4096]; | ||||
| 	int err, n; | ||||
| 
 | ||||
| 	err = errno; | ||||
| 
 | ||||
| 	for (;;) { | ||||
| 		n = read(fd, buf, sizeof(buf)); | ||||
| 		if (n < 0) | ||||
| 			break; | ||||
| 		n -= 2; | ||||
| 
 | ||||
| 		switch (buf[0]) { | ||||
| 		case 'e': | ||||
| 			fprintf(stderr, "Error: %*.*s\n", n, n, buf + 2); | ||||
| 			break; | ||||
| 		case 'w': | ||||
| 			fprintf(stderr, "Warning: %*.*s\n", n, n, buf + 2); | ||||
| 			break; | ||||
| 		case 'i': | ||||
| 			fprintf(stderr, "Info: %*.*s\n", n, n, buf + 2); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	errno = err; | ||||
| } | ||||
| 
 | ||||
| static __attribute__((noreturn)) | ||||
| void mount_error(int fd, const char *s) | ||||
| { | ||||
| 	check_messages(fd); | ||||
| 	fprintf(stderr, "%s: %m\n", s); | ||||
| 	exit(1); | ||||
| } | ||||
| 
 | ||||
| /* Hope -1 isn't a syscall */ | ||||
| #ifndef __NR_fsopen | ||||
| #define __NR_fsopen -1 | ||||
| #endif | ||||
| #ifndef __NR_fsmount | ||||
| #define __NR_fsmount -1 | ||||
| #endif | ||||
| #ifndef __NR_fsconfig | ||||
| #define __NR_fsconfig -1 | ||||
| #endif | ||||
| #ifndef __NR_move_mount | ||||
| #define __NR_move_mount -1 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| static inline int fsopen(const char *fs_name, unsigned int flags) | ||||
| { | ||||
| 	return syscall(__NR_fsopen, fs_name, flags); | ||||
| } | ||||
| 
 | ||||
| static inline int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags) | ||||
| { | ||||
| 	return syscall(__NR_fsmount, fsfd, flags, ms_flags); | ||||
| } | ||||
| 
 | ||||
| static inline int fsconfig(int fsfd, unsigned int cmd, | ||||
| 			   const char *key, const void *val, int aux) | ||||
| { | ||||
| 	return syscall(__NR_fsconfig, fsfd, cmd, key, val, aux); | ||||
| } | ||||
| 
 | ||||
| static inline int move_mount(int from_dfd, const char *from_pathname, | ||||
| 			     int to_dfd, const char *to_pathname, | ||||
| 			     unsigned int flags) | ||||
| { | ||||
| 	return syscall(__NR_move_mount, | ||||
| 		       from_dfd, from_pathname, | ||||
| 		       to_dfd, to_pathname, flags); | ||||
| } | ||||
| 
 | ||||
| #define E_fsconfig(fd, cmd, key, val, aux)				\ | ||||
| 	do {								\ | ||||
| 		if (fsconfig(fd, cmd, key, val, aux) == -1)		\ | ||||
| 			mount_error(fd, key ?: "create");		\ | ||||
| 	} while (0) | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fsfd, mfd; | ||||
| 
 | ||||
| 	/* Mount a publically available AFS filesystem */ | ||||
| 	fsfd = fsopen("afs", 0); | ||||
| 	if (fsfd == -1) { | ||||
| 		perror("fsopen"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	E_fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "#grand.central.org:root.cell.", 0); | ||||
| 	E_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); | ||||
| 
 | ||||
| 	mfd = fsmount(fsfd, 0, MOUNT_ATTR_RDONLY); | ||||
| 	if (mfd < 0) | ||||
| 		mount_error(fsfd, "fsmount"); | ||||
| 	E(close(fsfd)); | ||||
| 
 | ||||
| 	if (move_mount(mfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH) < 0) { | ||||
| 		perror("move_mount"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	E(close(mfd)); | ||||
| 	exit(0); | ||||
| } | ||||
|  | @ -25,13 +25,21 @@ | |||
| #include <sys/types.h> | ||||
| #include <linux/stat.h> | ||||
| #include <linux/fcntl.h> | ||||
| #define statx foo | ||||
| #define statx_timestamp foo_timestamp | ||||
| #include <sys/stat.h> | ||||
| #undef statx | ||||
| #undef statx_timestamp | ||||
| 
 | ||||
| #define AT_STATX_SYNC_TYPE	0x6000 | ||||
| #define AT_STATX_SYNC_AS_STAT	0x0000 | ||||
| #define AT_STATX_FORCE_SYNC	0x2000 | ||||
| #define AT_STATX_DONT_SYNC	0x4000 | ||||
| 
 | ||||
| #ifndef __NR_statx | ||||
| #define __NR_statx -1 | ||||
| #endif | ||||
| 
 | ||||
| static __attribute__((unused)) | ||||
| ssize_t statx(int dfd, const char *filename, unsigned flags, | ||||
| 	      unsigned int mask, struct statx *buffer) | ||||
|  | @ -157,7 +165,8 @@ static void dump_statx(struct statx *stx) | |||
| 			"?dai?c??"	/*  7- 0	0x00000000-000000ff */ | ||||
| 			; | ||||
| 
 | ||||
| 		printf("Attributes: %016llx (", stx->stx_attributes); | ||||
| 		printf("Attributes: %016llx (", | ||||
| 		       (unsigned long long)stx->stx_attributes); | ||||
| 		for (byte = 64 - 8; byte >= 0; byte -= 8) { | ||||
| 			bits = stx->stx_attributes >> byte; | ||||
| 			mbits = stx->stx_attributes_mask >> byte; | ||||
		Loading…
	
		Reference in a new issue
	
	 David Howells
						David Howells