blob: 5a7eb0c79839ed59830209baa94cf08afa3a351e [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{
142 int len, n;
143 char *name, *resolved, *end;
144
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';
167 len = strlen(link) + strlen(name) + 1;
168
169 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700170 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 n = -ENOMEM;
172 goto out_free;
173 }
174
175 sprintf(resolved, "%s%s", link, name);
Richard Weinberger7c950992015-03-03 23:55:49 +0100176 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700178 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180 out_free:
Richard Weinberger7c950992015-03-03 23:55:49 +0100181 __putname(name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700182 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183}
184
David Howells0a370e52008-02-07 00:15:50 -0800185static struct inode *hostfs_iget(struct super_block *sb)
186{
Al Viro52b209f2010-06-06 18:43:19 -0400187 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800188 if (!inode)
189 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800190 return inode;
191}
192
James Hogan9e443bc2013-11-14 21:15:13 +0000193static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194{
Jeff Dike84b3db02007-10-16 01:27:13 -0700195 /*
196 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 * struct statfs still has 32-bit versions for most of these fields,
198 * so we convert them here
199 */
200 int err;
201 long long f_blocks;
202 long long f_bfree;
203 long long f_bavail;
204 long long f_files;
205 long long f_ffree;
206
Al Viro601d2c32010-06-06 17:53:01 -0400207 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
209 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700210 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700211 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700212 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 sf->f_blocks = f_blocks;
214 sf->f_bfree = f_bfree;
215 sf->f_bavail = f_bavail;
216 sf->f_files = f_files;
217 sf->f_ffree = f_ffree;
218 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700219 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220}
221
222static struct inode *hostfs_alloc_inode(struct super_block *sb)
223{
224 struct hostfs_inode_info *hi;
225
Vladimir Davydov5d097052016-01-14 15:18:21 -0800226 hi = kmalloc(sizeof(*hi), GFP_KERNEL_ACCOUNT);
Jeff Dike84b3db02007-10-16 01:27:13 -0700227 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700228 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400229 hi->fd = -1;
James Hogan371fdab2013-03-27 10:47:14 +0000230 hi->mode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 inode_init_once(&hi->vfs_inode);
Richard Weinberger69886e62015-02-27 22:55:20 +0100232 mutex_init(&hi->open_mutex);
Jeff Dikef1adc052007-05-08 00:23:18 -0700233 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234}
235
Al Viroe971a6d2010-06-06 15:16:17 -0400236static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
Johannes Weiner91b0abe2014-04-03 14:47:49 -0700238 truncate_inode_pages_final(&inode->i_data);
Jan Karadbd57682012-05-03 14:48:02 +0200239 clear_inode(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700240 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 close_file(&HOSTFS_I(inode)->fd);
242 HOSTFS_I(inode)->fd = -1;
243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244}
245
Al Viro08ccfc52019-04-15 20:12:11 -0400246static void hostfs_free_inode(struct inode *inode)
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100247{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100248 kfree(HOSTFS_I(inode));
249}
250
Al Viro34c80b12011-12-08 21:32:45 -0500251static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800252{
Al Viro34c80b12011-12-08 21:32:45 -0500253 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800254 size_t offset = strlen(root_ino) + 1;
255
256 if (strlen(root_path) > offset)
Kees Cooka068acf2015-09-04 15:44:57 -0700257 seq_show_option(seq, root_path + offset, NULL);
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800258
Richard Weinberger7f74a662015-03-04 00:00:54 +0100259 if (append)
260 seq_puts(seq, ",append");
261
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800262 return 0;
263}
264
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800265static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 .alloc_inode = hostfs_alloc_inode,
Al Viro08ccfc52019-04-15 20:12:11 -0400267 .free_inode = hostfs_free_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400268 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800270 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271};
272
James Hogan9e443bc2013-11-14 21:15:13 +0000273static int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
275 void *dir;
276 char *name;
277 unsigned long long next, ino;
278 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100279 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Al Viroc5322222010-06-06 20:42:10 -0400281 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700282 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700283 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400285 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700286 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700287 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400288 next = ctx->pos;
Richard Weinberger0c9bd632015-03-24 15:47:38 +0100289 seek_dir(dir, next);
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100290 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400291 if (!dir_emit(ctx, name, len, ino, type))
292 break;
293 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 }
295 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700296 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100299static int hostfs_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
301 char *name;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100302 fmode_t mode;
Al Virof8ad8502010-06-06 23:49:18 -0400303 int err;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100304 int r, w, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700307 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700308 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Al Virof8ad8502010-06-06 23:49:18 -0400310 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Al Virof8ad8502010-06-06 23:49:18 -0400312retry:
Richard Weinbergera9d19582015-03-04 22:39:48 +0100313 r = w = 0;
314
Al Virof8ad8502010-06-06 23:49:18 -0400315 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400317 if (mode & FMODE_WRITE)
Richard Weinberger112a5da2015-03-04 00:05:11 +0100318 r = w = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Al Viroc5322222010-06-06 20:42:10 -0400320 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700321 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700322 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400325 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700326 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700327 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400328
Richard Weinberger69886e62015-02-27 22:55:20 +0100329 mutex_lock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400330 /* somebody else had handled it first? */
331 if ((mode & HOSTFS_I(ino)->mode) == mode) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100332 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Richard Weinbergeraf955652015-02-27 22:56:28 +0100333 close_file(&fd);
Al Virof8ad8502010-06-06 23:49:18 -0400334 return 0;
335 }
336 if ((mode | HOSTFS_I(ino)->mode) != mode) {
337 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100338 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400339 close_file(&fd);
340 goto retry;
341 }
342 if (HOSTFS_I(ino)->fd == -1) {
343 HOSTFS_I(ino)->fd = fd;
344 } else {
345 err = replace_file(fd, HOSTFS_I(ino)->fd);
346 close_file(&fd);
347 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100348 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400349 return err;
350 }
351 }
352 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100353 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Jeff Dikef1adc052007-05-08 00:23:18 -0700355 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
Richard Weinberger65984ff2013-08-04 17:23:51 +0000358static int hostfs_file_release(struct inode *inode, struct file *file)
359{
360 filemap_write_and_wait(inode->i_mapping);
361
362 return 0;
363}
364
James Hogan9e443bc2013-11-14 21:15:13 +0000365static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
366 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
Josef Bacik02c24a82011-07-16 20:44:56 -0400368 struct inode *inode = file->f_mapping->host;
369 int ret;
370
Jeff Layton3b49c9a2017-07-07 15:20:52 -0400371 ret = file_write_and_wait_range(file, start, end);
Josef Bacik02c24a82011-07-16 20:44:56 -0400372 if (ret)
373 return ret;
374
Al Viro59551022016-01-22 15:40:57 -0500375 inode_lock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400376 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
Al Viro59551022016-01-22 15:40:57 -0500377 inode_unlock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400378
379 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800382static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 .llseek = generic_file_llseek,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200384 .splice_read = generic_file_splice_read,
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);
Deepa Dinamani95582b02018-05-08 19:36:02 -0700552 ino->i_atime = timespec_to_timespec64(st.atime);
553 ino->i_mtime = timespec_to_timespec64(st.mtime);
554 ino->i_ctime = timespec_to_timespec64(st.ctime);
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
James Hogan9e443bc2013-11-14 21:15:13 +0000560static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
561 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
James Hogan9e443bc2013-11-14 21:15:13 +0000659static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
660 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
James Hogan9e443bc2013-11-14 21:15:13 +0000672static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 char *file;
675 int err;
676
Al Viroc5322222010-06-06 20:42:10 -0400677 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700678 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400680 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700681 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682}
683
James Hogan9e443bc2013-11-14 21:15:13 +0000684static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
686 char *file;
687 int err;
688
Al Viroc5322222010-06-06 20:42:10 -0400689 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return -ENOMEM;
Dominik Brodowski63801612018-03-11 11:34:48 +0100691 err = hostfs_do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400692 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700693 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694}
695
Al Viro1a67aaf2011-07-26 01:52:52 -0400696static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697{
698 struct inode *inode;
699 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800700 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
David Howells0a370e52008-02-07 00:15:50 -0800702 inode = hostfs_iget(dir->i_sb);
703 if (IS_ERR(inode)) {
704 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400709 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700710 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 goto out_put;
712
713 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800714 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Vegard Nossum9f2dfda2015-12-16 21:59:56 +0100715 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 goto out_free;
717
718 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400719 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400720 if (err)
721 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700724 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400727 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 out_put:
729 iput(inode);
730 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700731 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
733
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200734static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
735 struct inode *new_dir, struct dentry *new_dentry,
736 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200738 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 int err;
740
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200741 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
742 return -EINVAL;
743
744 old_name = dentry_name(old_dentry);
745 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700746 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200747 new_name = dentry_name(new_dentry);
748 if (new_name == NULL) {
749 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700750 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200752 if (!flags)
753 err = rename_file(old_name, new_name);
754 else
755 err = rename2_file(old_name, new_name, flags);
756
757 __putname(old_name);
758 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700759 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760}
761
James Hogan9e443bc2013-11-14 21:15:13 +0000762static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
764 char *name;
765 int r = 0, w = 0, x = 0, err;
766
Al Viro10556cb2011-06-20 19:28:19 -0400767 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100768 return -ECHILD;
769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (desired & MAY_READ) r = 1;
771 if (desired & MAY_WRITE) w = 1;
772 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400773 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700774 if (name == NULL)
775 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
777 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700778 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 err = 0;
780 else
781 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400782 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700783 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400784 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return err;
786}
787
James Hogan9e443bc2013-11-14 21:15:13 +0000788static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
David Howells2b0143b2015-03-17 22:25:59 +0000790 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 struct hostfs_iattr attrs;
792 char *name;
793 int err;
794
Christoph Hellwig10257742010-06-04 11:30:02 +0200795 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700796
Jan Kara31051c82016-05-26 16:55:18 +0200797 err = setattr_prepare(dentry, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 if (err)
799 return err;
800
Jeff Dike84b3db02007-10-16 01:27:13 -0700801 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 attr->ia_valid &= ~ATTR_SIZE;
803
804 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700805 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 attrs.ia_valid |= HOSTFS_ATTR_MODE;
807 attrs.ia_mode = attr->ia_mode;
808 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700809 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800811 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700813 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800815 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700817 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
819 attrs.ia_size = attr->ia_size;
820 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700821 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
Deepa Dinamani95582b02018-05-08 19:36:02 -0700823 attrs.ia_atime = timespec64_to_timespec(attr->ia_atime);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700825 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
Deepa Dinamani95582b02018-05-08 19:36:02 -0700827 attrs.ia_mtime = timespec64_to_timespec(attr->ia_mtime);
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;
Deepa Dinamani95582b02018-05-08 19:36:02 -0700831 attrs.ia_ctime = timespec64_to_timespec(attr->ia_ctime);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700833 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
835 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700836 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
838 }
Al Viroc5322222010-06-06 20:42:10 -0400839 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700840 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700841 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700842 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400843 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700844 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700845 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Christoph Hellwig10257742010-06-04 11:30:02 +0200847 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200848 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200849 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200850
851 setattr_copy(inode, attr);
852 mark_inode_dirty(inode);
853 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854}
855
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800856static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 .permission = hostfs_permission,
858 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859};
860
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800861static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 .create = hostfs_create,
863 .lookup = hostfs_lookup,
864 .link = hostfs_link,
865 .unlink = hostfs_unlink,
866 .symlink = hostfs_symlink,
867 .mkdir = hostfs_mkdir,
868 .rmdir = hostfs_rmdir,
869 .mknod = hostfs_mknod,
Miklos Szeredi2773bf02016-09-27 11:03:58 +0200870 .rename = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 .permission = hostfs_permission,
872 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873};
874
Al Viro6b255392015-11-17 10:20:54 -0500875static const char *hostfs_get_link(struct dentry *dentry,
Al Virofceef392015-12-29 15:58:39 -0500876 struct inode *inode,
877 struct delayed_call *done)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
Al Viro6b255392015-11-17 10:20:54 -0500879 char *link;
880 if (!dentry)
881 return ERR_PTR(-ECHILD);
Al Virofceef392015-12-29 15:58:39 -0500882 link = kmalloc(PATH_MAX, GFP_KERNEL);
Al Virod0352d32010-06-06 21:51:16 -0400883 if (link) {
884 char *path = dentry_name(dentry);
885 int err = -ENOMEM;
886 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400887 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400888 if (err == PATH_MAX)
889 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400890 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400891 }
892 if (err < 0) {
Al Virofceef392015-12-29 15:58:39 -0500893 kfree(link);
Al Viro680baac2015-05-02 13:32:22 -0400894 return ERR_PTR(err);
Al Virod0352d32010-06-06 21:51:16 -0400895 }
896 } else {
Al Viro680baac2015-05-02 13:32:22 -0400897 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
Al Virod0352d32010-06-06 21:51:16 -0400899
Al Virofceef392015-12-29 15:58:39 -0500900 set_delayed_call(done, kfree_link, link);
901 return link;
Al Virod0352d32010-06-06 21:51:16 -0400902}
903
904static const struct inode_operations hostfs_link_iops = {
Al Viro6b255392015-11-17 10:20:54 -0500905 .get_link = hostfs_get_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906};
907
908static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
909{
910 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700911 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 int err;
913
914 sb->s_blocksize = 1024;
915 sb->s_blocksize_bits = 10;
916 sb->s_magic = HOSTFS_SUPER_MAGIC;
917 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400918 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700919 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800921 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700922 if (req_root == NULL)
923 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400926 sb->s_fs_info = host_root_path =
927 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700928 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 goto out;
930
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700931 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Al Viro52b209f2010-06-06 18:43:19 -0400933 root_inode = new_inode(sb);
934 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400935 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Al Viro4754b822010-06-06 20:33:12 -0400937 err = read_name(root_inode, host_root_path);
938 if (err)
939 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400940
Al Viro4754b822010-06-06 20:33:12 -0400941 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400942 char *name = follow_link(host_root_path);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300943 if (IS_ERR(name)) {
Al Viro52b209f2010-06-06 18:43:19 -0400944 err = PTR_ERR(name);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300945 goto out_put;
946 }
947 err = read_name(root_inode, name);
Al Viro52b209f2010-06-06 18:43:19 -0400948 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400949 if (err)
950 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500954 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700955 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500956 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Jeff Dikef1adc052007-05-08 00:23:18 -0700958 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Jeff Dikef1adc052007-05-08 00:23:18 -0700960out_put:
961 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700962out:
963 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964}
965
Al Viro3c26ff62010-07-25 11:46:36 +0400966static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700967 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400968 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
Al Viro3c26ff62010-07-25 11:46:36 +0400970 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971}
972
Al Viro601d2c32010-06-06 17:53:01 -0400973static void hostfs_kill_sb(struct super_block *s)
974{
975 kill_anon_super(s);
976 kfree(s->s_fs_info);
977}
978
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979static struct file_system_type hostfs_type = {
980 .owner = THIS_MODULE,
981 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400982 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400983 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 .fs_flags = 0,
985};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700986MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988static int __init init_hostfs(void)
989{
Jeff Dikef1adc052007-05-08 00:23:18 -0700990 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
993static void __exit exit_hostfs(void)
994{
995 unregister_filesystem(&hostfs_type);
996}
997
998module_init(init_hostfs)
999module_exit(exit_hostfs)
1000MODULE_LICENSE("GPL");