blob: d5c9d886cd9f7bc9efdfda6edc2fdf0b4c059b3d [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,
Johannes Berg1568cb02021-07-06 23:12:42 +0200384 .splice_write = iter_file_splice_write,
Al Viroaad4f8b2014-04-02 14:33:16 -0400385 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400386 .write_iter = generic_file_write_iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 .mmap = generic_file_mmap,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100388 .open = hostfs_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000389 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 .fsync = hostfs_fsync,
391};
392
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800393static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .llseek = generic_file_llseek,
Al Viro552a9d42016-05-12 19:49:30 -0400395 .iterate_shared = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 .read = generic_read_dir,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100397 .open = hostfs_open,
398 .fsync = hostfs_fsync,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399};
400
James Hogan9e443bc2013-11-14 21:15:13 +0000401static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
403 struct address_space *mapping = page->mapping;
404 struct inode *inode = mapping->host;
405 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100406 loff_t base = page_offset(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300407 int count = PAGE_SIZE;
408 int end_index = inode->i_size >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 int err;
410
411 if (page->index >= end_index)
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300412 count = inode->i_size & (PAGE_SIZE-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414 buffer = kmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700417 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 ClearPageUptodate(page);
419 goto out;
420 }
421
422 if (base > inode->i_size)
423 inode->i_size = base;
424
425 if (PageError(page))
426 ClearPageError(page);
427 err = 0;
428
429 out:
430 kunmap(page);
431
432 unlock_page(page);
433 return err;
434}
435
James Hogan9e443bc2013-11-14 21:15:13 +0000436static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100439 loff_t start = page_offset(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100440 int bytes_read, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 buffer = kmap(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100443 bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300444 PAGE_SIZE);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100445 if (bytes_read < 0) {
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100446 ClearPageUptodate(page);
447 SetPageError(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100448 ret = bytes_read;
Jeff Dike84b3db02007-10-16 01:27:13 -0700449 goto out;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300452 memset(buffer + bytes_read, 0, PAGE_SIZE - bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100454 ClearPageError(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 SetPageUptodate(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100456
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 out:
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100458 flush_dcache_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 kunmap(page);
460 unlock_page(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100461 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462}
463
James Hogan9e443bc2013-11-14 21:15:13 +0000464static int hostfs_write_begin(struct file *file, struct address_space *mapping,
465 loff_t pos, unsigned len, unsigned flags,
466 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467{
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300468 pgoff_t index = pos >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Nick Piggin54566b22009-01-04 12:00:53 -0800470 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700471 if (!*pagep)
472 return -ENOMEM;
473 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474}
475
James Hogan9e443bc2013-11-14 21:15:13 +0000476static int hostfs_write_end(struct file *file, struct address_space *mapping,
477 loff_t pos, unsigned len, unsigned copied,
478 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700481 void *buffer;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300482 unsigned from = pos & (PAGE_SIZE - 1);
Nick Pigginae361ff2007-10-16 01:25:17 -0700483 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700486 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700488
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300489 if (!PageUptodate(page) && err == PAGE_SIZE)
Nick Pigginae361ff2007-10-16 01:25:17 -0700490 SetPageUptodate(page);
491
Jeff Dike84b3db02007-10-16 01:27:13 -0700492 /*
493 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700494 * i_size against the last byte written.
495 */
496 if (err > 0 && (pos > inode->i_size))
497 inode->i_size = pos;
498 unlock_page(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300499 put_page(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700500
Jeff Dikef1adc052007-05-08 00:23:18 -0700501 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502}
503
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700504static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 .writepage = hostfs_writepage,
506 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700507 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700508 .write_begin = hostfs_write_begin,
509 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510};
511
Al Viro4754b822010-06-06 20:33:12 -0400512static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
Al Viro4754b822010-06-06 20:33:12 -0400514 dev_t rdev;
515 struct hostfs_stat st;
516 int err = stat_file(name, &st, -1);
517 if (err)
518 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Al Viro5e2df282010-06-06 19:38:18 -0400520 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400521 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Al Viro4754b822010-06-06 20:33:12 -0400523 switch (st.mode & S_IFMT) {
524 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400525 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400526 break;
527 case S_IFDIR:
528 ino->i_op = &hostfs_dir_iops;
529 ino->i_fop = &hostfs_dir_fops;
530 break;
531 case S_IFCHR:
532 case S_IFBLK:
533 case S_IFIFO:
534 case S_IFSOCK:
535 init_special_inode(ino, st.mode & S_IFMT, rdev);
536 ino->i_op = &hostfs_iops;
537 break;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100538 case S_IFREG:
Al Viro4754b822010-06-06 20:33:12 -0400539 ino->i_op = &hostfs_iops;
540 ino->i_fop = &hostfs_file_fops;
541 ino->i_mapping->a_ops = &hostfs_aops;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100542 break;
543 default:
544 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 }
Al Viro4754b822010-06-06 20:33:12 -0400546
547 ino->i_ino = st.ino;
548 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200549 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800550 i_uid_write(ino, st.uid);
551 i_gid_write(ino, st.gid);
Arnd Bergmannbca30262018-06-12 15:31:17 +0200552 ino->i_atime = (struct timespec64){ st.atime.tv_sec, st.atime.tv_nsec };
553 ino->i_mtime = (struct timespec64){ st.mtime.tv_sec, st.mtime.tv_nsec };
554 ino->i_ctime = (struct timespec64){ st.ctime.tv_sec, st.ctime.tv_nsec };
Al Viro4754b822010-06-06 20:33:12 -0400555 ino->i_size = st.size;
556 ino->i_blocks = st.blocks;
557 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
Christian Brauner549c7292021-01-21 14:19:43 +0100560static int hostfs_create(struct user_namespace *mnt_userns, struct inode *dir,
561 struct dentry *dentry, umode_t mode, bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562{
563 struct inode *inode;
564 char *name;
565 int error, fd;
566
David Howells0a370e52008-02-07 00:15:50 -0800567 inode = hostfs_iget(dir->i_sb);
568 if (IS_ERR(inode)) {
569 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700570 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400574 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700575 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 goto out_put;
577
Richard Weinbergera718c922015-05-04 14:50:29 +0200578 fd = file_create(name, mode & 0777);
Al Viro4754b822010-06-06 20:33:12 -0400579 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400581 else
Al Viro5e2df282010-06-06 19:38:18 -0400582 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Al Viroe9193052010-06-06 23:16:34 -0400584 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700585 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 goto out_put;
587
588 HOSTFS_I(inode)->fd = fd;
589 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
590 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700591 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
593 out_put:
594 iput(inode);
595 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700596 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597}
598
James Hogan9e443bc2013-11-14 21:15:13 +0000599static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
600 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 struct inode *inode;
603 char *name;
604 int err;
605
David Howells0a370e52008-02-07 00:15:50 -0800606 inode = hostfs_iget(ino->i_sb);
Al Viro50f30742018-06-23 20:27:29 -0400607 if (IS_ERR(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 goto out;
609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400611 name = dentry_name(dentry);
Al Viro50f30742018-06-23 20:27:29 -0400612 if (name) {
613 err = read_name(inode, name);
614 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
Al Viro50f30742018-06-23 20:27:29 -0400616 if (err) {
617 iput(inode);
618 inode = (err == -ENOENT) ? NULL : ERR_PTR(err);
619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 out:
Al Viro50f30742018-06-23 20:27:29 -0400621 return d_splice_alias(inode, dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622}
623
James Hogan9e443bc2013-11-14 21:15:13 +0000624static int hostfs_link(struct dentry *to, struct inode *ino,
625 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626{
Jeff Dikef1adc052007-05-08 00:23:18 -0700627 char *from_name, *to_name;
628 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Al Viroc5322222010-06-06 20:42:10 -0400630 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700631 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400632 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700633 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400634 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700635 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700637 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400638 __putname(from_name);
639 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700640 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
James Hogan9e443bc2013-11-14 21:15:13 +0000643static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
645 char *file;
646 int err;
647
Jeff Dike84b3db02007-10-16 01:27:13 -0700648 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Al Virof8d7e182010-06-06 23:19:04 -0400651 if ((file = dentry_name(dentry)) == NULL)
652 return -ENOMEM;
653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400655 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700656 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657}
658
Christian Brauner549c7292021-01-21 14:19:43 +0100659static int hostfs_symlink(struct user_namespace *mnt_userns, struct inode *ino,
660 struct dentry *dentry, const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661{
662 char *file;
663 int err;
664
Al Viroc5322222010-06-06 20:42:10 -0400665 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700666 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400668 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700669 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670}
671
Christian Brauner549c7292021-01-21 14:19:43 +0100672static int hostfs_mkdir(struct user_namespace *mnt_userns, struct inode *ino,
673 struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
675 char *file;
676 int err;
677
Al Viroc5322222010-06-06 20:42:10 -0400678 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700679 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400681 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700682 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683}
684
James Hogan9e443bc2013-11-14 21:15:13 +0000685static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 char *file;
688 int err;
689
Al Viroc5322222010-06-06 20:42:10 -0400690 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700691 return -ENOMEM;
Dominik Brodowski63801612018-03-11 11:34:48 +0100692 err = hostfs_do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400693 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700694 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
Christian Brauner549c7292021-01-21 14:19:43 +0100697static int hostfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
698 struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699{
700 struct inode *inode;
701 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800702 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
David Howells0a370e52008-02-07 00:15:50 -0800704 inode = hostfs_iget(dir->i_sb);
705 if (IS_ERR(inode)) {
706 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400711 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700712 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 goto out_put;
714
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800715 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Vegard Nossum9f2dfda2015-12-16 21:59:56 +0100716 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 goto out_free;
718
719 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400720 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400721 if (err)
722 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700725 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400728 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 out_put:
730 iput(inode);
731 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700732 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733}
734
Christian Brauner549c7292021-01-21 14:19:43 +0100735static int hostfs_rename2(struct user_namespace *mnt_userns,
736 struct inode *old_dir, struct dentry *old_dentry,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200737 struct inode *new_dir, struct dentry *new_dentry,
738 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200740 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 int err;
742
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200743 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
744 return -EINVAL;
745
746 old_name = dentry_name(old_dentry);
747 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700748 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200749 new_name = dentry_name(new_dentry);
750 if (new_name == NULL) {
751 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700752 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200754 if (!flags)
755 err = rename_file(old_name, new_name);
756 else
757 err = rename2_file(old_name, new_name, flags);
758
759 __putname(old_name);
760 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700761 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762}
763
Christian Brauner549c7292021-01-21 14:19:43 +0100764static int hostfs_permission(struct user_namespace *mnt_userns,
765 struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
767 char *name;
768 int r = 0, w = 0, x = 0, err;
769
Al Viro10556cb22011-06-20 19:28:19 -0400770 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100771 return -ECHILD;
772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if (desired & MAY_READ) r = 1;
774 if (desired & MAY_WRITE) w = 1;
775 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400776 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700777 if (name == NULL)
778 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700781 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 err = 0;
783 else
784 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400785 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700786 if (!err)
Christian Brauner47291ba2021-01-21 14:19:24 +0100787 err = generic_permission(&init_user_ns, ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 return err;
789}
790
Christian Brauner549c7292021-01-21 14:19:43 +0100791static int hostfs_setattr(struct user_namespace *mnt_userns,
792 struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
David Howells2b0143b2015-03-17 22:25:59 +0000794 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 struct hostfs_iattr attrs;
796 char *name;
797 int err;
798
Christoph Hellwig10257742010-06-04 11:30:02 +0200799 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700800
Christian Brauner2f221d62021-01-21 14:19:26 +0100801 err = setattr_prepare(&init_user_ns, dentry, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 if (err)
803 return err;
804
Jeff Dike84b3db02007-10-16 01:27:13 -0700805 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 attr->ia_valid &= ~ATTR_SIZE;
807
808 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700809 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 attrs.ia_valid |= HOSTFS_ATTR_MODE;
811 attrs.ia_mode = attr->ia_mode;
812 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700813 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800815 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700817 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800819 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700821 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
823 attrs.ia_size = attr->ia_size;
824 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700825 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
Arnd Bergmannbca30262018-06-12 15:31:17 +0200827 attrs.ia_atime = (struct hostfs_timespec)
828 { attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700830 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
Arnd Bergmannbca30262018-06-12 15:31:17 +0200832 attrs.ia_mtime = (struct hostfs_timespec)
833 { attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700835 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
Arnd Bergmannbca30262018-06-12 15:31:17 +0200837 attrs.ia_ctime = (struct hostfs_timespec)
838 { attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700840 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
842 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700843 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
845 }
Al Viroc5322222010-06-06 20:42:10 -0400846 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700847 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700848 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700849 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400850 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700851 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700852 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
Christoph Hellwig10257742010-06-04 11:30:02 +0200854 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200855 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200856 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200857
Christian Brauner2f221d62021-01-21 14:19:26 +0100858 setattr_copy(&init_user_ns, inode, attr);
Christoph Hellwig10257742010-06-04 11:30:02 +0200859 mark_inode_dirty(inode);
860 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861}
862
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800863static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 .permission = hostfs_permission,
865 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866};
867
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800868static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 .create = hostfs_create,
870 .lookup = hostfs_lookup,
871 .link = hostfs_link,
872 .unlink = hostfs_unlink,
873 .symlink = hostfs_symlink,
874 .mkdir = hostfs_mkdir,
875 .rmdir = hostfs_rmdir,
876 .mknod = hostfs_mknod,
Miklos Szeredi2773bf02016-09-27 11:03:58 +0200877 .rename = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 .permission = hostfs_permission,
879 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880};
881
Al Viro6b255392015-11-17 10:20:54 -0500882static const char *hostfs_get_link(struct dentry *dentry,
Al Virofceef392015-12-29 15:58:39 -0500883 struct inode *inode,
884 struct delayed_call *done)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
Al Viro6b255392015-11-17 10:20:54 -0500886 char *link;
887 if (!dentry)
888 return ERR_PTR(-ECHILD);
Al Virofceef392015-12-29 15:58:39 -0500889 link = kmalloc(PATH_MAX, GFP_KERNEL);
Al Virod0352d32010-06-06 21:51:16 -0400890 if (link) {
891 char *path = dentry_name(dentry);
892 int err = -ENOMEM;
893 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400894 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400895 if (err == PATH_MAX)
896 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400897 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400898 }
899 if (err < 0) {
Al Virofceef392015-12-29 15:58:39 -0500900 kfree(link);
Al Viro680baac2015-05-02 13:32:22 -0400901 return ERR_PTR(err);
Al Virod0352d32010-06-06 21:51:16 -0400902 }
903 } else {
Al Viro680baac2015-05-02 13:32:22 -0400904 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
Al Virod0352d32010-06-06 21:51:16 -0400906
Al Virofceef392015-12-29 15:58:39 -0500907 set_delayed_call(done, kfree_link, link);
908 return link;
Al Virod0352d32010-06-06 21:51:16 -0400909}
910
911static const struct inode_operations hostfs_link_iops = {
Al Viro6b255392015-11-17 10:20:54 -0500912 .get_link = hostfs_get_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913};
914
915static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
916{
917 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700918 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 int err;
920
921 sb->s_blocksize = 1024;
922 sb->s_blocksize_bits = 10;
923 sb->s_magic = HOSTFS_SUPER_MAGIC;
924 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400925 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700926 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200928 /* NULL is printed as '(null)' by printf(): avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700929 if (req_root == NULL)
930 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400933 sb->s_fs_info = host_root_path =
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200934 kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
Jeff Dike84b3db02007-10-16 01:27:13 -0700935 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 goto out;
937
Al Viro52b209f2010-06-06 18:43:19 -0400938 root_inode = new_inode(sb);
939 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400940 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Al Viro4754b822010-06-06 20:33:12 -0400942 err = read_name(root_inode, host_root_path);
943 if (err)
944 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400945
Al Viro4754b822010-06-06 20:33:12 -0400946 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400947 char *name = follow_link(host_root_path);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300948 if (IS_ERR(name)) {
Al Viro52b209f2010-06-06 18:43:19 -0400949 err = PTR_ERR(name);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300950 goto out_put;
951 }
952 err = read_name(root_inode, name);
Al Viro52b209f2010-06-06 18:43:19 -0400953 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400954 if (err)
955 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500959 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700960 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500961 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Jeff Dikef1adc052007-05-08 00:23:18 -0700963 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Jeff Dikef1adc052007-05-08 00:23:18 -0700965out_put:
966 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700967out:
968 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969}
970
Al Viro3c26ff62010-07-25 11:46:36 +0400971static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700972 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400973 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
Al Viro3c26ff62010-07-25 11:46:36 +0400975 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976}
977
Al Viro601d2c32010-06-06 17:53:01 -0400978static void hostfs_kill_sb(struct super_block *s)
979{
980 kill_anon_super(s);
981 kfree(s->s_fs_info);
982}
983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984static struct file_system_type hostfs_type = {
985 .owner = THIS_MODULE,
986 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400987 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400988 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 .fs_flags = 0,
990};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700991MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993static int __init init_hostfs(void)
994{
Johannes Berga15f1e42021-01-13 21:31:55 +0100995 hostfs_inode_cache = KMEM_CACHE(hostfs_inode_info, 0);
996 if (!hostfs_inode_cache)
997 return -ENOMEM;
Jeff Dikef1adc052007-05-08 00:23:18 -0700998 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999}
1000
1001static void __exit exit_hostfs(void)
1002{
1003 unregister_filesystem(&hostfs_type);
Johannes Berga15f1e42021-01-13 21:31:55 +01001004 kmem_cache_destroy(hostfs_inode_cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005}
1006
1007module_init(init_hostfs)
1008module_exit(exit_hostfs)
1009MODULE_LICENSE("GPL");