blob: 7d0c3dbb2898206ab77c54db916c7c70f81baa09 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jeff Dikef1adc052007-05-08 00:23:18 -07002 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 *
5 * Ported the filesystem routines to 2.5.
6 * 2003-02-10 Petr Baudis <pasky@ucw.cz>
7 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/fs.h>
James Hogan2b3b9bb2013-03-27 10:47:13 +000010#include <linux/magic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/module.h>
Jeff Dike84b3db02007-10-16 01:27:13 -070012#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/statfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090015#include <linux/slab.h>
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -080016#include <linux/seq_file.h>
Jiri Kosina6966a972008-02-09 00:10:14 -080017#include <linux/mount.h>
Al Virod0352d32010-06-06 21:51:16 -040018#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include "hostfs.h"
Al Viro37185b32012-10-08 03:27:32 +010020#include <init.h>
21#include <kern.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
23struct hostfs_inode_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 int fd;
Al Viroaeb5d722008-09-02 15:28:45 -040025 fmode_t mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 struct inode vfs_inode;
Richard Weinberger69886e62015-02-27 22:55:20 +010027 struct mutex open_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -070028};
29
30static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
31{
Jeff Dikef1adc052007-05-08 00:23:18 -070032 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070033}
34
Al Viro496ad9a2013-01-23 17:07:38 -050035#define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file))
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Johannes Berga15f1e42021-01-13 21:31:55 +010037static struct kmem_cache *hostfs_inode_cache;
38
Linus Torvalds1da177e2005-04-16 15:20:36 -070039/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080040static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070041static int append = 0;
42
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080043static const struct inode_operations hostfs_iops;
44static const struct inode_operations hostfs_dir_iops;
Al Virod0352d32010-06-06 21:51:16 -040045static const struct inode_operations hostfs_link_iops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifndef MODULE
48static int __init hostfs_args(char *options, int *add)
49{
50 char *ptr;
51
52 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070053 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070055 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 root_ino = options;
57
58 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070059 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070061 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070063 if (*options != '\0') {
64 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 append = 1;
66 else printf("hostfs_args - unsupported option - %s\n",
67 options);
68 }
69 options = ptr;
70 }
Jeff Dikef1adc052007-05-08 00:23:18 -070071 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
74__uml_setup("hostfs=", hostfs_args,
75"hostfs=<root dir>,<flags>,...\n"
76" This is used to set hostfs parameters. The root directory argument\n"
77" is used to confine all hostfs mounts to within the specified directory\n"
78" tree on the host. If this isn't specified, then a user inside UML can\n"
79" mount anything on the host that's accessible to the user that's running\n"
80" it.\n"
81" The only flag currently supported is 'append', which specifies that all\n"
82" files opened by hostfs will be opened in append mode.\n\n"
83);
84#endif
85
Al Viroe9193052010-06-06 23:16:34 -040086static char *__dentry_name(struct dentry *dentry, char *name)
87{
Nick Pigginec2447c2011-01-07 17:49:29 +110088 char *p = dentry_path_raw(dentry, name, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040089 char *root;
90 size_t len;
91
Al Viroe9193052010-06-06 23:16:34 -040092 root = dentry->d_sb->s_fs_info;
93 len = strlen(root);
94 if (IS_ERR(p)) {
95 __putname(name);
96 return NULL;
97 }
Richard Weinbergeraad50b12015-03-03 23:41:52 +010098
99 /*
100 * This function relies on the fact that dentry_path_raw() will place
101 * the path name at the end of the provided buffer.
102 */
103 BUG_ON(p + strlen(p) + 1 != name + PATH_MAX);
104
Al Viro850a4962010-08-18 06:18:57 -0400105 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -0400106 if (len > p - name) {
107 __putname(name);
108 return NULL;
109 }
Richard Weinbergerc278e812015-03-03 23:42:25 +0100110
111 if (p > name + len)
112 strcpy(name + len, p);
113
Al Viroe9193052010-06-06 23:16:34 -0400114 return name;
115}
116
Al Viroc5322222010-06-06 20:42:10 -0400117static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118{
Al Viroe9193052010-06-06 23:16:34 -0400119 char *name = __getname();
120 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700121 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
James Hogan9dcc5e82013-03-27 10:47:12 +0000123 return __dentry_name(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124}
125
Al Viroc5322222010-06-06 20:42:10 -0400126static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
128 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100129 char *name;
130
131 dentry = d_find_alias(ino);
132 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400133 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Nick Pigginec2447c2011-01-07 17:49:29 +1100135 name = dentry_name(dentry);
136
137 dput(dentry);
138
139 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140}
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static char *follow_link(char *link)
143{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 char *name, *resolved, *end;
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200145 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Al Viro7f6c4112021-03-25 14:12:34 -0400147 name = kmalloc(PATH_MAX, GFP_KERNEL);
Richard Weinberger7c950992015-03-03 23:55:49 +0100148 if (!name) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 n = -ENOMEM;
Richard Weinberger7c950992015-03-03 23:55:49 +0100150 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 }
Richard Weinberger7c950992015-03-03 23:55:49 +0100152
153 n = hostfs_do_readlink(link, name, PATH_MAX);
Jeff Dike84b3db02007-10-16 01:27:13 -0700154 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 goto out_free;
Richard Weinberger7c950992015-03-03 23:55:49 +0100156 else if (n == PATH_MAX) {
157 n = -E2BIG;
158 goto out_free;
159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Jeff Dike84b3db02007-10-16 01:27:13 -0700161 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700162 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700165 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700166 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 *(end + 1) = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200170 resolved = kasprintf(GFP_KERNEL, "%s%s", link, name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700171 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 n = -ENOMEM;
173 goto out_free;
174 }
175
Al Viro7f6c4112021-03-25 14:12:34 -0400176 kfree(name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700177 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179 out_free:
Al Viro7f6c4112021-03-25 14:12:34 -0400180 kfree(name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700181 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182}
183
David Howells0a370e52008-02-07 00:15:50 -0800184static struct inode *hostfs_iget(struct super_block *sb)
185{
Al Viro52b209f2010-06-06 18:43:19 -0400186 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800187 if (!inode)
188 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800189 return inode;
190}
191
James Hogan9e443bc2013-11-14 21:15:13 +0000192static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193{
Jeff Dike84b3db02007-10-16 01:27:13 -0700194 /*
195 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 * struct statfs still has 32-bit versions for most of these fields,
197 * so we convert them here
198 */
199 int err;
200 long long f_blocks;
201 long long f_bfree;
202 long long f_bavail;
203 long long f_files;
204 long long f_ffree;
205
Al Viro601d2c32010-06-06 17:53:01 -0400206 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
208 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700209 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700210 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700211 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 sf->f_blocks = f_blocks;
213 sf->f_bfree = f_bfree;
214 sf->f_bavail = f_bavail;
215 sf->f_files = f_files;
216 sf->f_ffree = f_ffree;
217 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700218 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219}
220
221static struct inode *hostfs_alloc_inode(struct super_block *sb)
222{
223 struct hostfs_inode_info *hi;
224
Johannes Berga15f1e42021-01-13 21:31:55 +0100225 hi = kmem_cache_alloc(hostfs_inode_cache, GFP_KERNEL_ACCOUNT);
Jeff Dike84b3db02007-10-16 01:27:13 -0700226 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700227 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400228 hi->fd = -1;
James Hogan371fdab2013-03-27 10:47:14 +0000229 hi->mode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 inode_init_once(&hi->vfs_inode);
Richard Weinberger69886e62015-02-27 22:55:20 +0100231 mutex_init(&hi->open_mutex);
Jeff Dikef1adc052007-05-08 00:23:18 -0700232 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233}
234
Al Viroe971a6d2010-06-06 15:16:17 -0400235static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
Johannes Weiner91b0abe2014-04-03 14:47:49 -0700237 truncate_inode_pages_final(&inode->i_data);
Jan Karadbd57682012-05-03 14:48:02 +0200238 clear_inode(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700239 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 close_file(&HOSTFS_I(inode)->fd);
241 HOSTFS_I(inode)->fd = -1;
242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
244
Al Viro08ccfc52019-04-15 20:12:11 -0400245static void hostfs_free_inode(struct inode *inode)
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100246{
Johannes Berga15f1e42021-01-13 21:31:55 +0100247 kmem_cache_free(hostfs_inode_cache, HOSTFS_I(inode));
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100248}
249
Al Viro34c80b12011-12-08 21:32:45 -0500250static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800251{
Al Viro34c80b12011-12-08 21:32:45 -0500252 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800253 size_t offset = strlen(root_ino) + 1;
254
255 if (strlen(root_path) > offset)
Kees Cooka068acf2015-09-04 15:44:57 -0700256 seq_show_option(seq, root_path + offset, NULL);
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800257
Richard Weinberger7f74a662015-03-04 00:00:54 +0100258 if (append)
259 seq_puts(seq, ",append");
260
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800261 return 0;
262}
263
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800264static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 .alloc_inode = hostfs_alloc_inode,
Al Viro08ccfc52019-04-15 20:12:11 -0400266 .free_inode = hostfs_free_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400267 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800269 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270};
271
James Hogan9e443bc2013-11-14 21:15:13 +0000272static int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273{
274 void *dir;
275 char *name;
276 unsigned long long next, ino;
277 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100278 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Al Viroc5322222010-06-06 20:42:10 -0400280 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700281 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700282 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400284 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700285 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700286 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400287 next = ctx->pos;
Richard Weinberger0c9bd632015-03-24 15:47:38 +0100288 seek_dir(dir, next);
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100289 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400290 if (!dir_emit(ctx, name, len, ino, type))
291 break;
292 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 }
294 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700295 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100298static int hostfs_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 char *name;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100301 fmode_t mode;
Al Virof8ad8502010-06-06 23:49:18 -0400302 int err;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100303 int r, w, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700306 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700307 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Al Virof8ad8502010-06-06 23:49:18 -0400309 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Al Virof8ad8502010-06-06 23:49:18 -0400311retry:
Richard Weinbergera9d19582015-03-04 22:39:48 +0100312 r = w = 0;
313
Al Virof8ad8502010-06-06 23:49:18 -0400314 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400316 if (mode & FMODE_WRITE)
Richard Weinberger112a5da2015-03-04 00:05:11 +0100317 r = w = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Al Virod692d392021-04-15 22:03:00 -0400319 name = dentry_name(file_dentry(file));
Jeff Dike84b3db02007-10-16 01:27:13 -0700320 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700321 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400324 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700325 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700326 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400327
Richard Weinberger69886e62015-02-27 22:55:20 +0100328 mutex_lock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400329 /* somebody else had handled it first? */
330 if ((mode & HOSTFS_I(ino)->mode) == mode) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100331 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Richard Weinbergeraf955652015-02-27 22:56:28 +0100332 close_file(&fd);
Al Virof8ad8502010-06-06 23:49:18 -0400333 return 0;
334 }
335 if ((mode | HOSTFS_I(ino)->mode) != mode) {
336 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100337 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400338 close_file(&fd);
339 goto retry;
340 }
341 if (HOSTFS_I(ino)->fd == -1) {
342 HOSTFS_I(ino)->fd = fd;
343 } else {
344 err = replace_file(fd, HOSTFS_I(ino)->fd);
345 close_file(&fd);
346 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100347 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400348 return err;
349 }
350 }
351 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100352 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Jeff Dikef1adc052007-05-08 00:23:18 -0700354 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
Richard Weinberger65984ff2013-08-04 17:23:51 +0000357static int hostfs_file_release(struct inode *inode, struct file *file)
358{
359 filemap_write_and_wait(inode->i_mapping);
360
361 return 0;
362}
363
James Hogan9e443bc2013-11-14 21:15:13 +0000364static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
365 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Josef Bacik02c24a82011-07-16 20:44:56 -0400367 struct inode *inode = file->f_mapping->host;
368 int ret;
369
Jeff Layton3b49c9a2017-07-07 15:20:52 -0400370 ret = file_write_and_wait_range(file, start, end);
Josef Bacik02c24a82011-07-16 20:44:56 -0400371 if (ret)
372 return ret;
373
Al Viro59551022016-01-22 15:40:57 -0500374 inode_lock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400375 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
Al Viro59551022016-01-22 15:40:57 -0500376 inode_unlock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400377
378 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379}
380
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800381static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 .llseek = generic_file_llseek,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200383 .splice_read = generic_file_splice_read,
Al Viroaad4f8b2014-04-02 14:33:16 -0400384 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400385 .write_iter = generic_file_write_iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 .mmap = generic_file_mmap,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100387 .open = hostfs_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000388 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 .fsync = hostfs_fsync,
390};
391
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800392static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 .llseek = generic_file_llseek,
Al Viro552a9d42016-05-12 19:49:30 -0400394 .iterate_shared = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 .read = generic_read_dir,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100396 .open = hostfs_open,
397 .fsync = hostfs_fsync,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398};
399
James Hogan9e443bc2013-11-14 21:15:13 +0000400static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401{
402 struct address_space *mapping = page->mapping;
403 struct inode *inode = mapping->host;
404 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100405 loff_t base = page_offset(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300406 int count = PAGE_SIZE;
407 int end_index = inode->i_size >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 int err;
409
410 if (page->index >= end_index)
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300411 count = inode->i_size & (PAGE_SIZE-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
413 buffer = kmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700416 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 ClearPageUptodate(page);
418 goto out;
419 }
420
421 if (base > inode->i_size)
422 inode->i_size = base;
423
424 if (PageError(page))
425 ClearPageError(page);
426 err = 0;
427
428 out:
429 kunmap(page);
430
431 unlock_page(page);
432 return err;
433}
434
James Hogan9e443bc2013-11-14 21:15:13 +0000435static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
437 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100438 loff_t start = page_offset(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100439 int bytes_read, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 buffer = kmap(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100442 bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300443 PAGE_SIZE);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100444 if (bytes_read < 0) {
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100445 ClearPageUptodate(page);
446 SetPageError(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100447 ret = bytes_read;
Jeff Dike84b3db02007-10-16 01:27:13 -0700448 goto out;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300451 memset(buffer + bytes_read, 0, PAGE_SIZE - bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100453 ClearPageError(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 SetPageUptodate(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100455
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 out:
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100457 flush_dcache_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 kunmap(page);
459 unlock_page(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100460 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461}
462
James Hogan9e443bc2013-11-14 21:15:13 +0000463static int hostfs_write_begin(struct file *file, struct address_space *mapping,
464 loff_t pos, unsigned len, unsigned flags,
465 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300467 pgoff_t index = pos >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Nick Piggin54566b22009-01-04 12:00:53 -0800469 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700470 if (!*pagep)
471 return -ENOMEM;
472 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473}
474
James Hogan9e443bc2013-11-14 21:15:13 +0000475static int hostfs_write_end(struct file *file, struct address_space *mapping,
476 loff_t pos, unsigned len, unsigned copied,
477 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700480 void *buffer;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300481 unsigned from = pos & (PAGE_SIZE - 1);
Nick Pigginae361ff2007-10-16 01:25:17 -0700482 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700485 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700487
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300488 if (!PageUptodate(page) && err == PAGE_SIZE)
Nick Pigginae361ff2007-10-16 01:25:17 -0700489 SetPageUptodate(page);
490
Jeff Dike84b3db02007-10-16 01:27:13 -0700491 /*
492 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700493 * i_size against the last byte written.
494 */
495 if (err > 0 && (pos > inode->i_size))
496 inode->i_size = pos;
497 unlock_page(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300498 put_page(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700499
Jeff Dikef1adc052007-05-08 00:23:18 -0700500 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501}
502
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700503static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 .writepage = hostfs_writepage,
505 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700506 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700507 .write_begin = hostfs_write_begin,
508 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509};
510
Al Viro4754b822010-06-06 20:33:12 -0400511static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
Al Viro4754b822010-06-06 20:33:12 -0400513 dev_t rdev;
514 struct hostfs_stat st;
515 int err = stat_file(name, &st, -1);
516 if (err)
517 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Al Viro5e2df282010-06-06 19:38:18 -0400519 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400520 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Al Viro4754b822010-06-06 20:33:12 -0400522 switch (st.mode & S_IFMT) {
523 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400524 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400525 break;
526 case S_IFDIR:
527 ino->i_op = &hostfs_dir_iops;
528 ino->i_fop = &hostfs_dir_fops;
529 break;
530 case S_IFCHR:
531 case S_IFBLK:
532 case S_IFIFO:
533 case S_IFSOCK:
534 init_special_inode(ino, st.mode & S_IFMT, rdev);
535 ino->i_op = &hostfs_iops;
536 break;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100537 case S_IFREG:
Al Viro4754b822010-06-06 20:33:12 -0400538 ino->i_op = &hostfs_iops;
539 ino->i_fop = &hostfs_file_fops;
540 ino->i_mapping->a_ops = &hostfs_aops;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100541 break;
542 default:
543 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 }
Al Viro4754b822010-06-06 20:33:12 -0400545
546 ino->i_ino = st.ino;
547 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200548 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800549 i_uid_write(ino, st.uid);
550 i_gid_write(ino, st.gid);
Arnd Bergmannbca30262018-06-12 15:31:17 +0200551 ino->i_atime = (struct timespec64){ st.atime.tv_sec, st.atime.tv_nsec };
552 ino->i_mtime = (struct timespec64){ st.mtime.tv_sec, st.mtime.tv_nsec };
553 ino->i_ctime = (struct timespec64){ st.ctime.tv_sec, st.ctime.tv_nsec };
Al Viro4754b822010-06-06 20:33:12 -0400554 ino->i_size = st.size;
555 ino->i_blocks = st.blocks;
556 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557}
558
Christian Brauner549c7292021-01-21 14:19:43 +0100559static int hostfs_create(struct user_namespace *mnt_userns, struct inode *dir,
560 struct dentry *dentry, umode_t mode, bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
562 struct inode *inode;
563 char *name;
564 int error, fd;
565
David Howells0a370e52008-02-07 00:15:50 -0800566 inode = hostfs_iget(dir->i_sb);
567 if (IS_ERR(inode)) {
568 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700569 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400573 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700574 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 goto out_put;
576
Richard Weinbergera718c922015-05-04 14:50:29 +0200577 fd = file_create(name, mode & 0777);
Al Viro4754b822010-06-06 20:33:12 -0400578 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400580 else
Al Viro5e2df282010-06-06 19:38:18 -0400581 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
Al Viroe9193052010-06-06 23:16:34 -0400583 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700584 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 goto out_put;
586
587 HOSTFS_I(inode)->fd = fd;
588 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
589 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700590 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
592 out_put:
593 iput(inode);
594 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700595 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596}
597
James Hogan9e443bc2013-11-14 21:15:13 +0000598static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
599 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600{
601 struct inode *inode;
602 char *name;
603 int err;
604
David Howells0a370e52008-02-07 00:15:50 -0800605 inode = hostfs_iget(ino->i_sb);
Al Viro50f30742018-06-23 20:27:29 -0400606 if (IS_ERR(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 goto out;
608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400610 name = dentry_name(dentry);
Al Viro50f30742018-06-23 20:27:29 -0400611 if (name) {
612 err = read_name(inode, name);
613 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
Al Viro50f30742018-06-23 20:27:29 -0400615 if (err) {
616 iput(inode);
617 inode = (err == -ENOENT) ? NULL : ERR_PTR(err);
618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 out:
Al Viro50f30742018-06-23 20:27:29 -0400620 return d_splice_alias(inode, dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622
James Hogan9e443bc2013-11-14 21:15:13 +0000623static int hostfs_link(struct dentry *to, struct inode *ino,
624 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
Jeff Dikef1adc052007-05-08 00:23:18 -0700626 char *from_name, *to_name;
627 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Al Viroc5322222010-06-06 20:42:10 -0400629 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700630 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400631 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700632 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400633 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700634 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700636 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400637 __putname(from_name);
638 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
James Hogan9e443bc2013-11-14 21:15:13 +0000642static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643{
644 char *file;
645 int err;
646
Jeff Dike84b3db02007-10-16 01:27:13 -0700647 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700648 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Al Virof8d7e182010-06-06 23:19:04 -0400650 if ((file = dentry_name(dentry)) == NULL)
651 return -ENOMEM;
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400654 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
657
Christian Brauner549c7292021-01-21 14:19:43 +0100658static int hostfs_symlink(struct user_namespace *mnt_userns, struct inode *ino,
659 struct dentry *dentry, const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660{
661 char *file;
662 int err;
663
Al Viroc5322222010-06-06 20:42:10 -0400664 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700665 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400667 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700668 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669}
670
Christian Brauner549c7292021-01-21 14:19:43 +0100671static int hostfs_mkdir(struct user_namespace *mnt_userns, struct inode *ino,
672 struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 char *file;
675 int err;
676
Al Viroc5322222010-06-06 20:42:10 -0400677 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700678 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400680 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700681 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682}
683
James Hogan9e443bc2013-11-14 21:15:13 +0000684static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
686 char *file;
687 int err;
688
Al Viroc5322222010-06-06 20:42:10 -0400689 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return -ENOMEM;
Dominik Brodowski63801612018-03-11 11:34:48 +0100691 err = hostfs_do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400692 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700693 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694}
695
Christian Brauner549c7292021-01-21 14:19:43 +0100696static int hostfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
697 struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
699 struct inode *inode;
700 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800701 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
David Howells0a370e52008-02-07 00:15:50 -0800703 inode = hostfs_iget(dir->i_sb);
704 if (IS_ERR(inode)) {
705 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400710 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700711 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 goto out_put;
713
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800714 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Vegard Nossum9f2dfda2015-12-16 21:59:56 +0100715 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 goto out_free;
717
718 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400719 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400720 if (err)
721 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700724 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400727 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 out_put:
729 iput(inode);
730 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700731 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
733
Christian Brauner549c7292021-01-21 14:19:43 +0100734static int hostfs_rename2(struct user_namespace *mnt_userns,
735 struct inode *old_dir, struct dentry *old_dentry,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200736 struct inode *new_dir, struct dentry *new_dentry,
737 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200739 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 int err;
741
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200742 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
743 return -EINVAL;
744
745 old_name = dentry_name(old_dentry);
746 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700747 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200748 new_name = dentry_name(new_dentry);
749 if (new_name == NULL) {
750 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700751 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200753 if (!flags)
754 err = rename_file(old_name, new_name);
755 else
756 err = rename2_file(old_name, new_name, flags);
757
758 __putname(old_name);
759 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700760 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761}
762
Christian Brauner549c7292021-01-21 14:19:43 +0100763static int hostfs_permission(struct user_namespace *mnt_userns,
764 struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
766 char *name;
767 int r = 0, w = 0, x = 0, err;
768
Al Viro10556cb22011-06-20 19:28:19 -0400769 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100770 return -ECHILD;
771
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 if (desired & MAY_READ) r = 1;
773 if (desired & MAY_WRITE) w = 1;
774 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400775 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700776 if (name == NULL)
777 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
779 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700780 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 err = 0;
782 else
783 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400784 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700785 if (!err)
Christian Brauner47291ba2021-01-21 14:19:24 +0100786 err = generic_permission(&init_user_ns, ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 return err;
788}
789
Christian Brauner549c7292021-01-21 14:19:43 +0100790static int hostfs_setattr(struct user_namespace *mnt_userns,
791 struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
David Howells2b0143b2015-03-17 22:25:59 +0000793 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 struct hostfs_iattr attrs;
795 char *name;
796 int err;
797
Christoph Hellwig10257742010-06-04 11:30:02 +0200798 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700799
Christian Brauner2f221d62021-01-21 14:19:26 +0100800 err = setattr_prepare(&init_user_ns, dentry, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 if (err)
802 return err;
803
Jeff Dike84b3db02007-10-16 01:27:13 -0700804 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 attr->ia_valid &= ~ATTR_SIZE;
806
807 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700808 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 attrs.ia_valid |= HOSTFS_ATTR_MODE;
810 attrs.ia_mode = attr->ia_mode;
811 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700812 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800814 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700816 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800818 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700820 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
822 attrs.ia_size = attr->ia_size;
823 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700824 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
Arnd Bergmannbca30262018-06-12 15:31:17 +0200826 attrs.ia_atime = (struct hostfs_timespec)
827 { attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700829 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
Arnd Bergmannbca30262018-06-12 15:31:17 +0200831 attrs.ia_mtime = (struct hostfs_timespec)
832 { attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700834 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
Arnd Bergmannbca30262018-06-12 15:31:17 +0200836 attrs.ia_ctime = (struct hostfs_timespec)
837 { attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
841 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700842 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
844 }
Al Viroc5322222010-06-06 20:42:10 -0400845 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700846 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700847 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700848 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400849 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700850 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700851 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Christoph Hellwig10257742010-06-04 11:30:02 +0200853 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200854 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200855 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200856
Christian Brauner2f221d62021-01-21 14:19:26 +0100857 setattr_copy(&init_user_ns, inode, attr);
Christoph Hellwig10257742010-06-04 11:30:02 +0200858 mark_inode_dirty(inode);
859 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800862static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 .permission = hostfs_permission,
864 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865};
866
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800867static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 .create = hostfs_create,
869 .lookup = hostfs_lookup,
870 .link = hostfs_link,
871 .unlink = hostfs_unlink,
872 .symlink = hostfs_symlink,
873 .mkdir = hostfs_mkdir,
874 .rmdir = hostfs_rmdir,
875 .mknod = hostfs_mknod,
Miklos Szeredi2773bf02016-09-27 11:03:58 +0200876 .rename = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 .permission = hostfs_permission,
878 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879};
880
Al Viro6b255392015-11-17 10:20:54 -0500881static const char *hostfs_get_link(struct dentry *dentry,
Al Virofceef392015-12-29 15:58:39 -0500882 struct inode *inode,
883 struct delayed_call *done)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
Al Viro6b255392015-11-17 10:20:54 -0500885 char *link;
886 if (!dentry)
887 return ERR_PTR(-ECHILD);
Al Virofceef392015-12-29 15:58:39 -0500888 link = kmalloc(PATH_MAX, GFP_KERNEL);
Al Virod0352d32010-06-06 21:51:16 -0400889 if (link) {
890 char *path = dentry_name(dentry);
891 int err = -ENOMEM;
892 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400893 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400894 if (err == PATH_MAX)
895 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400896 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400897 }
898 if (err < 0) {
Al Virofceef392015-12-29 15:58:39 -0500899 kfree(link);
Al Viro680baac2015-05-02 13:32:22 -0400900 return ERR_PTR(err);
Al Virod0352d32010-06-06 21:51:16 -0400901 }
902 } else {
Al Viro680baac2015-05-02 13:32:22 -0400903 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 }
Al Virod0352d32010-06-06 21:51:16 -0400905
Al Virofceef392015-12-29 15:58:39 -0500906 set_delayed_call(done, kfree_link, link);
907 return link;
Al Virod0352d32010-06-06 21:51:16 -0400908}
909
910static const struct inode_operations hostfs_link_iops = {
Al Viro6b255392015-11-17 10:20:54 -0500911 .get_link = hostfs_get_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912};
913
914static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
915{
916 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700917 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 int err;
919
920 sb->s_blocksize = 1024;
921 sb->s_blocksize_bits = 10;
922 sb->s_magic = HOSTFS_SUPER_MAGIC;
923 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400924 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700925 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200927 /* NULL is printed as '(null)' by printf(): avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700928 if (req_root == NULL)
929 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400932 sb->s_fs_info = host_root_path =
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200933 kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
Jeff Dike84b3db02007-10-16 01:27:13 -0700934 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 goto out;
936
Al Viro52b209f2010-06-06 18:43:19 -0400937 root_inode = new_inode(sb);
938 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400939 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Al Viro4754b822010-06-06 20:33:12 -0400941 err = read_name(root_inode, host_root_path);
942 if (err)
943 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400944
Al Viro4754b822010-06-06 20:33:12 -0400945 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400946 char *name = follow_link(host_root_path);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300947 if (IS_ERR(name)) {
Al Viro52b209f2010-06-06 18:43:19 -0400948 err = PTR_ERR(name);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300949 goto out_put;
950 }
951 err = read_name(root_inode, name);
Al Viro52b209f2010-06-06 18:43:19 -0400952 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400953 if (err)
954 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500958 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700959 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500960 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Jeff Dikef1adc052007-05-08 00:23:18 -0700962 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Jeff Dikef1adc052007-05-08 00:23:18 -0700964out_put:
965 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700966out:
967 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968}
969
Al Viro3c26ff62010-07-25 11:46:36 +0400970static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700971 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400972 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
Al Viro3c26ff62010-07-25 11:46:36 +0400974 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975}
976
Al Viro601d2c32010-06-06 17:53:01 -0400977static void hostfs_kill_sb(struct super_block *s)
978{
979 kill_anon_super(s);
980 kfree(s->s_fs_info);
981}
982
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983static struct file_system_type hostfs_type = {
984 .owner = THIS_MODULE,
985 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400986 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400987 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 .fs_flags = 0,
989};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700990MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992static int __init init_hostfs(void)
993{
Johannes Berga15f1e42021-01-13 21:31:55 +0100994 hostfs_inode_cache = KMEM_CACHE(hostfs_inode_info, 0);
995 if (!hostfs_inode_cache)
996 return -ENOMEM;
Jeff Dikef1adc052007-05-08 00:23:18 -0700997 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998}
999
1000static void __exit exit_hostfs(void)
1001{
1002 unregister_filesystem(&hostfs_type);
Johannes Berga15f1e42021-01-13 21:31:55 +01001003 kmem_cache_destroy(hostfs_inode_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004}
1005
1006module_init(init_hostfs)
1007module_exit(exit_hostfs)
1008MODULE_LICENSE("GPL");