blob: c070c0d8e3e977b7fbc830bb58ac302abc93f5da [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070037/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080038static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070039static int append = 0;
40
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080041static const struct inode_operations hostfs_iops;
42static const struct inode_operations hostfs_dir_iops;
Al Virod0352d32010-06-06 21:51:16 -040043static const struct inode_operations hostfs_link_iops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45#ifndef MODULE
46static int __init hostfs_args(char *options, int *add)
47{
48 char *ptr;
49
50 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070051 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070053 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 root_ino = options;
55
56 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070057 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070059 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070061 if (*options != '\0') {
62 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 append = 1;
64 else printf("hostfs_args - unsupported option - %s\n",
65 options);
66 }
67 options = ptr;
68 }
Jeff Dikef1adc052007-05-08 00:23:18 -070069 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
71
72__uml_setup("hostfs=", hostfs_args,
73"hostfs=<root dir>,<flags>,...\n"
74" This is used to set hostfs parameters. The root directory argument\n"
75" is used to confine all hostfs mounts to within the specified directory\n"
76" tree on the host. If this isn't specified, then a user inside UML can\n"
77" mount anything on the host that's accessible to the user that's running\n"
78" it.\n"
79" The only flag currently supported is 'append', which specifies that all\n"
80" files opened by hostfs will be opened in append mode.\n\n"
81);
82#endif
83
Al Viroe9193052010-06-06 23:16:34 -040084static char *__dentry_name(struct dentry *dentry, char *name)
85{
Nick Pigginec2447c2011-01-07 17:49:29 +110086 char *p = dentry_path_raw(dentry, name, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040087 char *root;
88 size_t len;
89
Al Viroe9193052010-06-06 23:16:34 -040090 root = dentry->d_sb->s_fs_info;
91 len = strlen(root);
92 if (IS_ERR(p)) {
93 __putname(name);
94 return NULL;
95 }
Richard Weinbergeraad50b12015-03-03 23:41:52 +010096
97 /*
98 * This function relies on the fact that dentry_path_raw() will place
99 * the path name at the end of the provided buffer.
100 */
101 BUG_ON(p + strlen(p) + 1 != name + PATH_MAX);
102
Al Viro850a4962010-08-18 06:18:57 -0400103 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -0400104 if (len > p - name) {
105 __putname(name);
106 return NULL;
107 }
Richard Weinbergerc278e812015-03-03 23:42:25 +0100108
109 if (p > name + len)
110 strcpy(name + len, p);
111
Al Viroe9193052010-06-06 23:16:34 -0400112 return name;
113}
114
Al Viroc5322222010-06-06 20:42:10 -0400115static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
Al Viroe9193052010-06-06 23:16:34 -0400117 char *name = __getname();
118 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700119 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
James Hogan9dcc5e82013-03-27 10:47:12 +0000121 return __dentry_name(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
Al Viroc5322222010-06-06 20:42:10 -0400124static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
126 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100127 char *name;
128
129 dentry = d_find_alias(ino);
130 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400131 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Nick Pigginec2447c2011-01-07 17:49:29 +1100133 name = dentry_name(dentry);
134
135 dput(dentry);
136
137 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140static char *follow_link(char *link)
141{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 char *name, *resolved, *end;
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200143 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Richard Weinberger7c950992015-03-03 23:55:49 +0100145 name = __getname();
146 if (!name) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 n = -ENOMEM;
Richard Weinberger7c950992015-03-03 23:55:49 +0100148 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 }
Richard Weinberger7c950992015-03-03 23:55:49 +0100150
151 n = hostfs_do_readlink(link, name, PATH_MAX);
Jeff Dike84b3db02007-10-16 01:27:13 -0700152 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 goto out_free;
Richard Weinberger7c950992015-03-03 23:55:49 +0100154 else if (n == PATH_MAX) {
155 n = -E2BIG;
156 goto out_free;
157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Jeff Dike84b3db02007-10-16 01:27:13 -0700159 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700160 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700163 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700164 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166 *(end + 1) = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200168 resolved = kasprintf(GFP_KERNEL, "%s%s", link, name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700169 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 n = -ENOMEM;
171 goto out_free;
172 }
173
Richard Weinberger7c950992015-03-03 23:55:49 +0100174 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700176 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178 out_free:
Richard Weinberger7c950992015-03-03 23:55:49 +0100179 __putname(name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700180 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181}
182
David Howells0a370e52008-02-07 00:15:50 -0800183static struct inode *hostfs_iget(struct super_block *sb)
184{
Al Viro52b209f2010-06-06 18:43:19 -0400185 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800186 if (!inode)
187 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800188 return inode;
189}
190
James Hogan9e443bc2013-11-14 21:15:13 +0000191static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Jeff Dike84b3db02007-10-16 01:27:13 -0700193 /*
194 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 * struct statfs still has 32-bit versions for most of these fields,
196 * so we convert them here
197 */
198 int err;
199 long long f_blocks;
200 long long f_bfree;
201 long long f_bavail;
202 long long f_files;
203 long long f_ffree;
204
Al Viro601d2c32010-06-06 17:53:01 -0400205 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
207 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700208 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700209 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700210 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 sf->f_blocks = f_blocks;
212 sf->f_bfree = f_bfree;
213 sf->f_bavail = f_bavail;
214 sf->f_files = f_files;
215 sf->f_ffree = f_ffree;
216 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700217 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218}
219
220static struct inode *hostfs_alloc_inode(struct super_block *sb)
221{
222 struct hostfs_inode_info *hi;
223
Vladimir Davydov5d097052016-01-14 15:18:21 -0800224 hi = kmalloc(sizeof(*hi), GFP_KERNEL_ACCOUNT);
Jeff Dike84b3db02007-10-16 01:27:13 -0700225 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700226 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400227 hi->fd = -1;
James Hogan371fdab2013-03-27 10:47:14 +0000228 hi->mode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 inode_init_once(&hi->vfs_inode);
Richard Weinberger69886e62015-02-27 22:55:20 +0100230 mutex_init(&hi->open_mutex);
Jeff Dikef1adc052007-05-08 00:23:18 -0700231 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232}
233
Al Viroe971a6d2010-06-06 15:16:17 -0400234static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235{
Johannes Weiner91b0abe2014-04-03 14:47:49 -0700236 truncate_inode_pages_final(&inode->i_data);
Jan Karadbd57682012-05-03 14:48:02 +0200237 clear_inode(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700238 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 close_file(&HOSTFS_I(inode)->fd);
240 HOSTFS_I(inode)->fd = -1;
241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
Al Viro08ccfc52019-04-15 20:12:11 -0400244static void hostfs_free_inode(struct inode *inode)
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100245{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100246 kfree(HOSTFS_I(inode));
247}
248
Al Viro34c80b12011-12-08 21:32:45 -0500249static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800250{
Al Viro34c80b12011-12-08 21:32:45 -0500251 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800252 size_t offset = strlen(root_ino) + 1;
253
254 if (strlen(root_path) > offset)
Kees Cooka068acf2015-09-04 15:44:57 -0700255 seq_show_option(seq, root_path + offset, NULL);
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800256
Richard Weinberger7f74a662015-03-04 00:00:54 +0100257 if (append)
258 seq_puts(seq, ",append");
259
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800260 return 0;
261}
262
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800263static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 .alloc_inode = hostfs_alloc_inode,
Al Viro08ccfc52019-04-15 20:12:11 -0400265 .free_inode = hostfs_free_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400266 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800268 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269};
270
James Hogan9e443bc2013-11-14 21:15:13 +0000271static int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{
273 void *dir;
274 char *name;
275 unsigned long long next, ino;
276 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100277 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Al Viroc5322222010-06-06 20:42:10 -0400279 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700280 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700281 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400283 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700284 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700285 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400286 next = ctx->pos;
Richard Weinberger0c9bd632015-03-24 15:47:38 +0100287 seek_dir(dir, next);
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100288 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400289 if (!dir_emit(ctx, name, len, ino, type))
290 break;
291 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 }
293 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700294 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
296
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100297static int hostfs_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
299 char *name;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100300 fmode_t mode;
Al Virof8ad8502010-06-06 23:49:18 -0400301 int err;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100302 int r, w, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700305 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700306 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Al Virof8ad8502010-06-06 23:49:18 -0400308 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Al Virof8ad8502010-06-06 23:49:18 -0400310retry:
Richard Weinbergera9d19582015-03-04 22:39:48 +0100311 r = w = 0;
312
Al Virof8ad8502010-06-06 23:49:18 -0400313 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400315 if (mode & FMODE_WRITE)
Richard Weinberger112a5da2015-03-04 00:05:11 +0100316 r = w = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Al Viroc5322222010-06-06 20:42:10 -0400318 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700319 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700320 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400323 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700324 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700325 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400326
Richard Weinberger69886e62015-02-27 22:55:20 +0100327 mutex_lock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400328 /* somebody else had handled it first? */
329 if ((mode & HOSTFS_I(ino)->mode) == mode) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100330 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Richard Weinbergeraf955652015-02-27 22:56:28 +0100331 close_file(&fd);
Al Virof8ad8502010-06-06 23:49:18 -0400332 return 0;
333 }
334 if ((mode | HOSTFS_I(ino)->mode) != mode) {
335 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100336 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400337 close_file(&fd);
338 goto retry;
339 }
340 if (HOSTFS_I(ino)->fd == -1) {
341 HOSTFS_I(ino)->fd = fd;
342 } else {
343 err = replace_file(fd, HOSTFS_I(ino)->fd);
344 close_file(&fd);
345 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100346 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400347 return err;
348 }
349 }
350 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100351 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Jeff Dikef1adc052007-05-08 00:23:18 -0700353 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354}
355
Richard Weinberger65984ff2013-08-04 17:23:51 +0000356static int hostfs_file_release(struct inode *inode, struct file *file)
357{
358 filemap_write_and_wait(inode->i_mapping);
359
360 return 0;
361}
362
James Hogan9e443bc2013-11-14 21:15:13 +0000363static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
364 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Josef Bacik02c24a82011-07-16 20:44:56 -0400366 struct inode *inode = file->f_mapping->host;
367 int ret;
368
Jeff Layton3b49c9a2017-07-07 15:20:52 -0400369 ret = file_write_and_wait_range(file, start, end);
Josef Bacik02c24a82011-07-16 20:44:56 -0400370 if (ret)
371 return ret;
372
Al Viro59551022016-01-22 15:40:57 -0500373 inode_lock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400374 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
Al Viro59551022016-01-22 15:40:57 -0500375 inode_unlock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400376
377 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378}
379
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800380static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 .llseek = generic_file_llseek,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200382 .splice_read = generic_file_splice_read,
Al Viroaad4f8b2014-04-02 14:33:16 -0400383 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400384 .write_iter = generic_file_write_iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 .mmap = generic_file_mmap,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100386 .open = hostfs_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000387 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 .fsync = hostfs_fsync,
389};
390
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800391static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 .llseek = generic_file_llseek,
Al Viro552a9d42016-05-12 19:49:30 -0400393 .iterate_shared = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .read = generic_read_dir,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100395 .open = hostfs_open,
396 .fsync = hostfs_fsync,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397};
398
James Hogan9e443bc2013-11-14 21:15:13 +0000399static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
401 struct address_space *mapping = page->mapping;
402 struct inode *inode = mapping->host;
403 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100404 loff_t base = page_offset(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300405 int count = PAGE_SIZE;
406 int end_index = inode->i_size >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 int err;
408
409 if (page->index >= end_index)
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300410 count = inode->i_size & (PAGE_SIZE-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
412 buffer = kmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700415 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 ClearPageUptodate(page);
417 goto out;
418 }
419
420 if (base > inode->i_size)
421 inode->i_size = base;
422
423 if (PageError(page))
424 ClearPageError(page);
425 err = 0;
426
427 out:
428 kunmap(page);
429
430 unlock_page(page);
431 return err;
432}
433
James Hogan9e443bc2013-11-14 21:15:13 +0000434static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
436 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100437 loff_t start = page_offset(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100438 int bytes_read, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 buffer = kmap(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100441 bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300442 PAGE_SIZE);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100443 if (bytes_read < 0) {
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100444 ClearPageUptodate(page);
445 SetPageError(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100446 ret = bytes_read;
Jeff Dike84b3db02007-10-16 01:27:13 -0700447 goto out;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300450 memset(buffer + bytes_read, 0, PAGE_SIZE - bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100452 ClearPageError(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 SetPageUptodate(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100454
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 out:
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100456 flush_dcache_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 kunmap(page);
458 unlock_page(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100459 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
James Hogan9e443bc2013-11-14 21:15:13 +0000462static int hostfs_write_begin(struct file *file, struct address_space *mapping,
463 loff_t pos, unsigned len, unsigned flags,
464 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300466 pgoff_t index = pos >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Nick Piggin54566b22009-01-04 12:00:53 -0800468 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700469 if (!*pagep)
470 return -ENOMEM;
471 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472}
473
James Hogan9e443bc2013-11-14 21:15:13 +0000474static int hostfs_write_end(struct file *file, struct address_space *mapping,
475 loff_t pos, unsigned len, unsigned copied,
476 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700479 void *buffer;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300480 unsigned from = pos & (PAGE_SIZE - 1);
Nick Pigginae361ff2007-10-16 01:25:17 -0700481 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700484 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700486
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300487 if (!PageUptodate(page) && err == PAGE_SIZE)
Nick Pigginae361ff2007-10-16 01:25:17 -0700488 SetPageUptodate(page);
489
Jeff Dike84b3db02007-10-16 01:27:13 -0700490 /*
491 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700492 * i_size against the last byte written.
493 */
494 if (err > 0 && (pos > inode->i_size))
495 inode->i_size = pos;
496 unlock_page(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300497 put_page(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700498
Jeff Dikef1adc052007-05-08 00:23:18 -0700499 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700502static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 .writepage = hostfs_writepage,
504 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700505 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700506 .write_begin = hostfs_write_begin,
507 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508};
509
Al Viro4754b822010-06-06 20:33:12 -0400510static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511{
Al Viro4754b822010-06-06 20:33:12 -0400512 dev_t rdev;
513 struct hostfs_stat st;
514 int err = stat_file(name, &st, -1);
515 if (err)
516 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Al Viro5e2df282010-06-06 19:38:18 -0400518 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400519 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Al Viro4754b822010-06-06 20:33:12 -0400521 switch (st.mode & S_IFMT) {
522 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400523 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400524 break;
525 case S_IFDIR:
526 ino->i_op = &hostfs_dir_iops;
527 ino->i_fop = &hostfs_dir_fops;
528 break;
529 case S_IFCHR:
530 case S_IFBLK:
531 case S_IFIFO:
532 case S_IFSOCK:
533 init_special_inode(ino, st.mode & S_IFMT, rdev);
534 ino->i_op = &hostfs_iops;
535 break;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100536 case S_IFREG:
Al Viro4754b822010-06-06 20:33:12 -0400537 ino->i_op = &hostfs_iops;
538 ino->i_fop = &hostfs_file_fops;
539 ino->i_mapping->a_ops = &hostfs_aops;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100540 break;
541 default:
542 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 }
Al Viro4754b822010-06-06 20:33:12 -0400544
545 ino->i_ino = st.ino;
546 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200547 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800548 i_uid_write(ino, st.uid);
549 i_gid_write(ino, st.gid);
Arnd Bergmannbca30262018-06-12 15:31:17 +0200550 ino->i_atime = (struct timespec64){ st.atime.tv_sec, st.atime.tv_nsec };
551 ino->i_mtime = (struct timespec64){ st.mtime.tv_sec, st.mtime.tv_nsec };
552 ino->i_ctime = (struct timespec64){ st.ctime.tv_sec, st.ctime.tv_nsec };
Al Viro4754b822010-06-06 20:33:12 -0400553 ino->i_size = st.size;
554 ino->i_blocks = st.blocks;
555 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556}
557
James Hogan9e443bc2013-11-14 21:15:13 +0000558static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
559 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
561 struct inode *inode;
562 char *name;
563 int error, fd;
564
David Howells0a370e52008-02-07 00:15:50 -0800565 inode = hostfs_iget(dir->i_sb);
566 if (IS_ERR(inode)) {
567 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700568 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400572 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700573 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 goto out_put;
575
Richard Weinbergera718c922015-05-04 14:50:29 +0200576 fd = file_create(name, mode & 0777);
Al Viro4754b822010-06-06 20:33:12 -0400577 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400579 else
Al Viro5e2df282010-06-06 19:38:18 -0400580 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Al Viroe9193052010-06-06 23:16:34 -0400582 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700583 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 goto out_put;
585
586 HOSTFS_I(inode)->fd = fd;
587 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
588 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700589 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
591 out_put:
592 iput(inode);
593 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700594 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595}
596
James Hogan9e443bc2013-11-14 21:15:13 +0000597static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
598 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
600 struct inode *inode;
601 char *name;
602 int err;
603
David Howells0a370e52008-02-07 00:15:50 -0800604 inode = hostfs_iget(ino->i_sb);
Al Viro50f30742018-06-23 20:27:29 -0400605 if (IS_ERR(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 goto out;
607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400609 name = dentry_name(dentry);
Al Viro50f30742018-06-23 20:27:29 -0400610 if (name) {
611 err = read_name(inode, name);
612 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
Al Viro50f30742018-06-23 20:27:29 -0400614 if (err) {
615 iput(inode);
616 inode = (err == -ENOENT) ? NULL : ERR_PTR(err);
617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 out:
Al Viro50f30742018-06-23 20:27:29 -0400619 return d_splice_alias(inode, dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620}
621
James Hogan9e443bc2013-11-14 21:15:13 +0000622static int hostfs_link(struct dentry *to, struct inode *ino,
623 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
Jeff Dikef1adc052007-05-08 00:23:18 -0700625 char *from_name, *to_name;
626 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Al Viroc5322222010-06-06 20:42:10 -0400628 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700629 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400630 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700631 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400632 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700633 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700635 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400636 __putname(from_name);
637 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700638 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639}
640
James Hogan9e443bc2013-11-14 21:15:13 +0000641static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
643 char *file;
644 int err;
645
Jeff Dike84b3db02007-10-16 01:27:13 -0700646 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700647 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Al Virof8d7e182010-06-06 23:19:04 -0400649 if ((file = dentry_name(dentry)) == NULL)
650 return -ENOMEM;
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400653 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700654 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
656
James Hogan9e443bc2013-11-14 21:15:13 +0000657static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
658 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659{
660 char *file;
661 int err;
662
Al Viroc5322222010-06-06 20:42:10 -0400663 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700664 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400666 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700667 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668}
669
James Hogan9e443bc2013-11-14 21:15:13 +0000670static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671{
672 char *file;
673 int err;
674
Al Viroc5322222010-06-06 20:42:10 -0400675 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400678 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700679 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
James Hogan9e443bc2013-11-14 21:15:13 +0000682static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
684 char *file;
685 int err;
686
Al Viroc5322222010-06-06 20:42:10 -0400687 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return -ENOMEM;
Dominik Brodowski63801612018-03-11 11:34:48 +0100689 err = hostfs_do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400690 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700691 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692}
693
Al Viro1a67aaf2011-07-26 01:52:52 -0400694static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
696 struct inode *inode;
697 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800698 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
David Howells0a370e52008-02-07 00:15:50 -0800700 inode = hostfs_iget(dir->i_sb);
701 if (IS_ERR(inode)) {
702 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800704 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400707 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700708 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 goto out_put;
710
711 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800712 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Vegard Nossum9f2dfda2015-12-16 21:59:56 +0100713 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 goto out_free;
715
716 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400717 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400718 if (err)
719 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700722 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400725 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 out_put:
727 iput(inode);
728 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700729 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730}
731
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200732static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
733 struct inode *new_dir, struct dentry *new_dentry,
734 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200736 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 int err;
738
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200739 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
740 return -EINVAL;
741
742 old_name = dentry_name(old_dentry);
743 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700744 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200745 new_name = dentry_name(new_dentry);
746 if (new_name == NULL) {
747 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700748 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200750 if (!flags)
751 err = rename_file(old_name, new_name);
752 else
753 err = rename2_file(old_name, new_name, flags);
754
755 __putname(old_name);
756 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700757 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758}
759
James Hogan9e443bc2013-11-14 21:15:13 +0000760static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
762 char *name;
763 int r = 0, w = 0, x = 0, err;
764
Al Viro10556cb2011-06-20 19:28:19 -0400765 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100766 return -ECHILD;
767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 if (desired & MAY_READ) r = 1;
769 if (desired & MAY_WRITE) w = 1;
770 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400771 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700772 if (name == NULL)
773 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
775 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700776 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 err = 0;
778 else
779 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400780 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700781 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400782 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return err;
784}
785
James Hogan9e443bc2013-11-14 21:15:13 +0000786static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787{
David Howells2b0143b2015-03-17 22:25:59 +0000788 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 struct hostfs_iattr attrs;
790 char *name;
791 int err;
792
Christoph Hellwig10257742010-06-04 11:30:02 +0200793 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700794
Jan Kara31051c82016-05-26 16:55:18 +0200795 err = setattr_prepare(dentry, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 if (err)
797 return err;
798
Jeff Dike84b3db02007-10-16 01:27:13 -0700799 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 attr->ia_valid &= ~ATTR_SIZE;
801
802 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700803 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 attrs.ia_valid |= HOSTFS_ATTR_MODE;
805 attrs.ia_mode = attr->ia_mode;
806 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700807 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800809 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700811 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800813 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700815 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
817 attrs.ia_size = attr->ia_size;
818 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700819 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
Arnd Bergmannbca30262018-06-12 15:31:17 +0200821 attrs.ia_atime = (struct hostfs_timespec)
822 { attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700824 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
Arnd Bergmannbca30262018-06-12 15:31:17 +0200826 attrs.ia_mtime = (struct hostfs_timespec)
827 { attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700829 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
Arnd Bergmannbca30262018-06-12 15:31:17 +0200831 attrs.ia_ctime = (struct hostfs_timespec)
832 { attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700834 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
836 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700837 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
839 }
Al Viroc5322222010-06-06 20:42:10 -0400840 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700841 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700842 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700843 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400844 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700845 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700846 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Christoph Hellwig10257742010-06-04 11:30:02 +0200848 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200849 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200850 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200851
852 setattr_copy(inode, attr);
853 mark_inode_dirty(inode);
854 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855}
856
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800857static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 .permission = hostfs_permission,
859 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860};
861
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800862static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 .create = hostfs_create,
864 .lookup = hostfs_lookup,
865 .link = hostfs_link,
866 .unlink = hostfs_unlink,
867 .symlink = hostfs_symlink,
868 .mkdir = hostfs_mkdir,
869 .rmdir = hostfs_rmdir,
870 .mknod = hostfs_mknod,
Miklos Szeredi2773bf02016-09-27 11:03:58 +0200871 .rename = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 .permission = hostfs_permission,
873 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874};
875
Al Viro6b255392015-11-17 10:20:54 -0500876static const char *hostfs_get_link(struct dentry *dentry,
Al Virofceef392015-12-29 15:58:39 -0500877 struct inode *inode,
878 struct delayed_call *done)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
Al Viro6b255392015-11-17 10:20:54 -0500880 char *link;
881 if (!dentry)
882 return ERR_PTR(-ECHILD);
Al Virofceef392015-12-29 15:58:39 -0500883 link = kmalloc(PATH_MAX, GFP_KERNEL);
Al Virod0352d32010-06-06 21:51:16 -0400884 if (link) {
885 char *path = dentry_name(dentry);
886 int err = -ENOMEM;
887 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400888 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400889 if (err == PATH_MAX)
890 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400891 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400892 }
893 if (err < 0) {
Al Virofceef392015-12-29 15:58:39 -0500894 kfree(link);
Al Viro680baac2015-05-02 13:32:22 -0400895 return ERR_PTR(err);
Al Virod0352d32010-06-06 21:51:16 -0400896 }
897 } else {
Al Viro680baac2015-05-02 13:32:22 -0400898 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 }
Al Virod0352d32010-06-06 21:51:16 -0400900
Al Virofceef392015-12-29 15:58:39 -0500901 set_delayed_call(done, kfree_link, link);
902 return link;
Al Virod0352d32010-06-06 21:51:16 -0400903}
904
905static const struct inode_operations hostfs_link_iops = {
Al Viro6b255392015-11-17 10:20:54 -0500906 .get_link = hostfs_get_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907};
908
909static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
910{
911 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700912 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 int err;
914
915 sb->s_blocksize = 1024;
916 sb->s_blocksize_bits = 10;
917 sb->s_magic = HOSTFS_SUPER_MAGIC;
918 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400919 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700920 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200922 /* NULL is printed as '(null)' by printf(): avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700923 if (req_root == NULL)
924 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400927 sb->s_fs_info = host_root_path =
Andy Shevchenkob58c4e92020-03-20 15:07:35 +0200928 kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
Jeff Dike84b3db02007-10-16 01:27:13 -0700929 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 goto out;
931
Al Viro52b209f2010-06-06 18:43:19 -0400932 root_inode = new_inode(sb);
933 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400934 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Al Viro4754b822010-06-06 20:33:12 -0400936 err = read_name(root_inode, host_root_path);
937 if (err)
938 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400939
Al Viro4754b822010-06-06 20:33:12 -0400940 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400941 char *name = follow_link(host_root_path);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300942 if (IS_ERR(name)) {
Al Viro52b209f2010-06-06 18:43:19 -0400943 err = PTR_ERR(name);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300944 goto out_put;
945 }
946 err = read_name(root_inode, name);
Al Viro52b209f2010-06-06 18:43:19 -0400947 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400948 if (err)
949 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500953 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700954 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500955 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Jeff Dikef1adc052007-05-08 00:23:18 -0700957 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Jeff Dikef1adc052007-05-08 00:23:18 -0700959out_put:
960 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700961out:
962 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963}
964
Al Viro3c26ff62010-07-25 11:46:36 +0400965static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700966 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400967 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
Al Viro3c26ff62010-07-25 11:46:36 +0400969 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970}
971
Al Viro601d2c32010-06-06 17:53:01 -0400972static void hostfs_kill_sb(struct super_block *s)
973{
974 kill_anon_super(s);
975 kfree(s->s_fs_info);
976}
977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978static struct file_system_type hostfs_type = {
979 .owner = THIS_MODULE,
980 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400981 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400982 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 .fs_flags = 0,
984};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700985MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987static int __init init_hostfs(void)
988{
Jeff Dikef1adc052007-05-08 00:23:18 -0700989 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990}
991
992static void __exit exit_hostfs(void)
993{
994 unregister_filesystem(&hostfs_type);
995}
996
997module_init(init_hostfs)
998module_exit(exit_hostfs)
999MODULE_LICENSE("GPL");