blob: 444c7b1703594403fb88c32efc5ae70af7c72f78 [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
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100246static void hostfs_i_callback(struct rcu_head *head)
247{
248 struct inode *inode = container_of(head, struct inode, i_rcu);
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100249 kfree(HOSTFS_I(inode));
250}
251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252static void hostfs_destroy_inode(struct inode *inode)
253{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100254 call_rcu(&inode->i_rcu, hostfs_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255}
256
Al Viro34c80b12011-12-08 21:32:45 -0500257static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800258{
Al Viro34c80b12011-12-08 21:32:45 -0500259 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800260 size_t offset = strlen(root_ino) + 1;
261
262 if (strlen(root_path) > offset)
Kees Cooka068acf2015-09-04 15:44:57 -0700263 seq_show_option(seq, root_path + offset, NULL);
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800264
Richard Weinberger7f74a662015-03-04 00:00:54 +0100265 if (append)
266 seq_puts(seq, ",append");
267
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800268 return 0;
269}
270
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800271static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400274 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800276 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277};
278
James Hogan9e443bc2013-11-14 21:15:13 +0000279static int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280{
281 void *dir;
282 char *name;
283 unsigned long long next, ino;
284 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100285 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Al Viroc5322222010-06-06 20:42:10 -0400287 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700288 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700289 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400291 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700292 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700293 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400294 next = ctx->pos;
Richard Weinberger0c9bd632015-03-24 15:47:38 +0100295 seek_dir(dir, next);
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100296 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400297 if (!dir_emit(ctx, name, len, ino, type))
298 break;
299 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700302 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303}
304
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100305static int hostfs_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
307 char *name;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100308 fmode_t mode;
Al Virof8ad8502010-06-06 23:49:18 -0400309 int err;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100310 int r, w, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700313 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700314 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Al Virof8ad8502010-06-06 23:49:18 -0400316 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Al Virof8ad8502010-06-06 23:49:18 -0400318retry:
Richard Weinbergera9d19582015-03-04 22:39:48 +0100319 r = w = 0;
320
Al Virof8ad8502010-06-06 23:49:18 -0400321 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400323 if (mode & FMODE_WRITE)
Richard Weinberger112a5da2015-03-04 00:05:11 +0100324 r = w = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Al Viroc5322222010-06-06 20:42:10 -0400326 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700327 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700328 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400331 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700332 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700333 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400334
Richard Weinberger69886e62015-02-27 22:55:20 +0100335 mutex_lock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400336 /* somebody else had handled it first? */
337 if ((mode & HOSTFS_I(ino)->mode) == mode) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100338 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Richard Weinbergeraf955652015-02-27 22:56:28 +0100339 close_file(&fd);
Al Virof8ad8502010-06-06 23:49:18 -0400340 return 0;
341 }
342 if ((mode | HOSTFS_I(ino)->mode) != mode) {
343 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100344 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400345 close_file(&fd);
346 goto retry;
347 }
348 if (HOSTFS_I(ino)->fd == -1) {
349 HOSTFS_I(ino)->fd = fd;
350 } else {
351 err = replace_file(fd, HOSTFS_I(ino)->fd);
352 close_file(&fd);
353 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100354 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400355 return err;
356 }
357 }
358 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100359 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Jeff Dikef1adc052007-05-08 00:23:18 -0700361 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
Richard Weinberger65984ff2013-08-04 17:23:51 +0000364static int hostfs_file_release(struct inode *inode, struct file *file)
365{
366 filemap_write_and_wait(inode->i_mapping);
367
368 return 0;
369}
370
James Hogan9e443bc2013-11-14 21:15:13 +0000371static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
372 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
Josef Bacik02c24a82011-07-16 20:44:56 -0400374 struct inode *inode = file->f_mapping->host;
375 int ret;
376
Jeff Layton3b49c9a2017-07-07 15:20:52 -0400377 ret = file_write_and_wait_range(file, start, end);
Josef Bacik02c24a82011-07-16 20:44:56 -0400378 if (ret)
379 return ret;
380
Al Viro59551022016-01-22 15:40:57 -0500381 inode_lock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400382 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
Al Viro59551022016-01-22 15:40:57 -0500383 inode_unlock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400384
385 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386}
387
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800388static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 .llseek = generic_file_llseek,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200390 .splice_read = generic_file_splice_read,
Al Viroaad4f8b2014-04-02 14:33:16 -0400391 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400392 .write_iter = generic_file_write_iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 .mmap = generic_file_mmap,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100394 .open = hostfs_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000395 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 .fsync = hostfs_fsync,
397};
398
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800399static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 .llseek = generic_file_llseek,
Al Viro552a9d42016-05-12 19:49:30 -0400401 .iterate_shared = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 .read = generic_read_dir,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100403 .open = hostfs_open,
404 .fsync = hostfs_fsync,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405};
406
James Hogan9e443bc2013-11-14 21:15:13 +0000407static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 struct address_space *mapping = page->mapping;
410 struct inode *inode = mapping->host;
411 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100412 loff_t base = page_offset(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300413 int count = PAGE_SIZE;
414 int end_index = inode->i_size >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 int err;
416
417 if (page->index >= end_index)
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300418 count = inode->i_size & (PAGE_SIZE-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
420 buffer = kmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
422 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700423 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 ClearPageUptodate(page);
425 goto out;
426 }
427
428 if (base > inode->i_size)
429 inode->i_size = base;
430
431 if (PageError(page))
432 ClearPageError(page);
433 err = 0;
434
435 out:
436 kunmap(page);
437
438 unlock_page(page);
439 return err;
440}
441
James Hogan9e443bc2013-11-14 21:15:13 +0000442static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
444 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100445 loff_t start = page_offset(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100446 int bytes_read, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 buffer = kmap(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100449 bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300450 PAGE_SIZE);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100451 if (bytes_read < 0) {
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100452 ClearPageUptodate(page);
453 SetPageError(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100454 ret = bytes_read;
Jeff Dike84b3db02007-10-16 01:27:13 -0700455 goto out;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300458 memset(buffer + bytes_read, 0, PAGE_SIZE - bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100460 ClearPageError(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 SetPageUptodate(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 out:
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100464 flush_dcache_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 kunmap(page);
466 unlock_page(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100467 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
James Hogan9e443bc2013-11-14 21:15:13 +0000470static int hostfs_write_begin(struct file *file, struct address_space *mapping,
471 loff_t pos, unsigned len, unsigned flags,
472 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300474 pgoff_t index = pos >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Nick Piggin54566b22009-01-04 12:00:53 -0800476 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700477 if (!*pagep)
478 return -ENOMEM;
479 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480}
481
James Hogan9e443bc2013-11-14 21:15:13 +0000482static int hostfs_write_end(struct file *file, struct address_space *mapping,
483 loff_t pos, unsigned len, unsigned copied,
484 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700487 void *buffer;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300488 unsigned from = pos & (PAGE_SIZE - 1);
Nick Pigginae361ff2007-10-16 01:25:17 -0700489 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700492 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700494
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300495 if (!PageUptodate(page) && err == PAGE_SIZE)
Nick Pigginae361ff2007-10-16 01:25:17 -0700496 SetPageUptodate(page);
497
Jeff Dike84b3db02007-10-16 01:27:13 -0700498 /*
499 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700500 * i_size against the last byte written.
501 */
502 if (err > 0 && (pos > inode->i_size))
503 inode->i_size = pos;
504 unlock_page(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300505 put_page(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700506
Jeff Dikef1adc052007-05-08 00:23:18 -0700507 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700510static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 .writepage = hostfs_writepage,
512 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700513 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700514 .write_begin = hostfs_write_begin,
515 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516};
517
Al Viro4754b822010-06-06 20:33:12 -0400518static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
Al Viro4754b822010-06-06 20:33:12 -0400520 dev_t rdev;
521 struct hostfs_stat st;
522 int err = stat_file(name, &st, -1);
523 if (err)
524 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Al Viro5e2df282010-06-06 19:38:18 -0400526 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400527 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Al Viro4754b822010-06-06 20:33:12 -0400529 switch (st.mode & S_IFMT) {
530 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400531 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400532 break;
533 case S_IFDIR:
534 ino->i_op = &hostfs_dir_iops;
535 ino->i_fop = &hostfs_dir_fops;
536 break;
537 case S_IFCHR:
538 case S_IFBLK:
539 case S_IFIFO:
540 case S_IFSOCK:
541 init_special_inode(ino, st.mode & S_IFMT, rdev);
542 ino->i_op = &hostfs_iops;
543 break;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100544 case S_IFREG:
Al Viro4754b822010-06-06 20:33:12 -0400545 ino->i_op = &hostfs_iops;
546 ino->i_fop = &hostfs_file_fops;
547 ino->i_mapping->a_ops = &hostfs_aops;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100548 break;
549 default:
550 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 }
Al Viro4754b822010-06-06 20:33:12 -0400552
553 ino->i_ino = st.ino;
554 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200555 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800556 i_uid_write(ino, st.uid);
557 i_gid_write(ino, st.gid);
Deepa Dinamani95582b02018-05-08 19:36:02 -0700558 ino->i_atime = timespec_to_timespec64(st.atime);
559 ino->i_mtime = timespec_to_timespec64(st.mtime);
560 ino->i_ctime = timespec_to_timespec64(st.ctime);
Al Viro4754b822010-06-06 20:33:12 -0400561 ino->i_size = st.size;
562 ino->i_blocks = st.blocks;
563 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564}
565
James Hogan9e443bc2013-11-14 21:15:13 +0000566static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
567 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
569 struct inode *inode;
570 char *name;
571 int error, fd;
572
David Howells0a370e52008-02-07 00:15:50 -0800573 inode = hostfs_iget(dir->i_sb);
574 if (IS_ERR(inode)) {
575 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700576 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400580 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700581 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 goto out_put;
583
Richard Weinbergera718c922015-05-04 14:50:29 +0200584 fd = file_create(name, mode & 0777);
Al Viro4754b822010-06-06 20:33:12 -0400585 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400587 else
Al Viro5e2df282010-06-06 19:38:18 -0400588 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Al Viroe9193052010-06-06 23:16:34 -0400590 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700591 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 goto out_put;
593
594 HOSTFS_I(inode)->fd = fd;
595 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
596 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700597 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 out_put:
600 iput(inode);
601 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700602 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603}
604
James Hogan9e443bc2013-11-14 21:15:13 +0000605static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
606 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
608 struct inode *inode;
609 char *name;
610 int err;
611
David Howells0a370e52008-02-07 00:15:50 -0800612 inode = hostfs_iget(ino->i_sb);
Al Viro50f30742018-06-23 20:27:29 -0400613 if (IS_ERR(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 goto out;
615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400617 name = dentry_name(dentry);
Al Viro50f30742018-06-23 20:27:29 -0400618 if (name) {
619 err = read_name(inode, name);
620 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 }
Al Viro50f30742018-06-23 20:27:29 -0400622 if (err) {
623 iput(inode);
624 inode = (err == -ENOENT) ? NULL : ERR_PTR(err);
625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 out:
Al Viro50f30742018-06-23 20:27:29 -0400627 return d_splice_alias(inode, dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628}
629
James Hogan9e443bc2013-11-14 21:15:13 +0000630static int hostfs_link(struct dentry *to, struct inode *ino,
631 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
Jeff Dikef1adc052007-05-08 00:23:18 -0700633 char *from_name, *to_name;
634 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Al Viroc5322222010-06-06 20:42:10 -0400636 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700637 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400638 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700639 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400640 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700641 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700643 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400644 __putname(from_name);
645 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700646 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
James Hogan9e443bc2013-11-14 21:15:13 +0000649static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650{
651 char *file;
652 int err;
653
Jeff Dike84b3db02007-10-16 01:27:13 -0700654 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Al Virof8d7e182010-06-06 23:19:04 -0400657 if ((file = dentry_name(dentry)) == NULL)
658 return -ENOMEM;
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400661 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700662 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663}
664
James Hogan9e443bc2013-11-14 21:15:13 +0000665static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
666 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
668 char *file;
669 int err;
670
Al Viroc5322222010-06-06 20:42:10 -0400671 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700672 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400674 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700675 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676}
677
James Hogan9e443bc2013-11-14 21:15:13 +0000678static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
680 char *file;
681 int err;
682
Al Viroc5322222010-06-06 20:42:10 -0400683 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700684 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400686 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700687 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688}
689
James Hogan9e443bc2013-11-14 21:15:13 +0000690static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
692 char *file;
693 int err;
694
Al Viroc5322222010-06-06 20:42:10 -0400695 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700696 return -ENOMEM;
Dominik Brodowski63801612018-03-11 11:34:48 +0100697 err = hostfs_do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400698 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700699 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
Al Viro1a67aaf2011-07-26 01:52:52 -0400702static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 struct inode *inode;
705 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800706 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
David Howells0a370e52008-02-07 00:15:50 -0800708 inode = hostfs_iget(dir->i_sb);
709 if (IS_ERR(inode)) {
710 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400715 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700716 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 goto out_put;
718
719 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800720 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Vegard Nossum9f2dfda2015-12-16 21:59:56 +0100721 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 goto out_free;
723
724 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400725 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400726 if (err)
727 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700730 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
732 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400733 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 out_put:
735 iput(inode);
736 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700737 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738}
739
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200740static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
741 struct inode *new_dir, struct dentry *new_dentry,
742 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200744 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 int err;
746
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200747 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
748 return -EINVAL;
749
750 old_name = dentry_name(old_dentry);
751 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700752 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200753 new_name = dentry_name(new_dentry);
754 if (new_name == NULL) {
755 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700756 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200758 if (!flags)
759 err = rename_file(old_name, new_name);
760 else
761 err = rename2_file(old_name, new_name, flags);
762
763 __putname(old_name);
764 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700765 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766}
767
James Hogan9e443bc2013-11-14 21:15:13 +0000768static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
770 char *name;
771 int r = 0, w = 0, x = 0, err;
772
Al Viro10556cb2011-06-20 19:28:19 -0400773 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100774 return -ECHILD;
775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 if (desired & MAY_READ) r = 1;
777 if (desired & MAY_WRITE) w = 1;
778 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400779 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700780 if (name == NULL)
781 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700784 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 err = 0;
786 else
787 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400788 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700789 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400790 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 return err;
792}
793
James Hogan9e443bc2013-11-14 21:15:13 +0000794static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
David Howells2b0143b2015-03-17 22:25:59 +0000796 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 struct hostfs_iattr attrs;
798 char *name;
799 int err;
800
Christoph Hellwig10257742010-06-04 11:30:02 +0200801 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700802
Jan Kara31051c82016-05-26 16:55:18 +0200803 err = setattr_prepare(dentry, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 if (err)
805 return err;
806
Jeff Dike84b3db02007-10-16 01:27:13 -0700807 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 attr->ia_valid &= ~ATTR_SIZE;
809
810 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700811 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 attrs.ia_valid |= HOSTFS_ATTR_MODE;
813 attrs.ia_mode = attr->ia_mode;
814 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700815 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800817 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700819 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800821 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700823 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
825 attrs.ia_size = attr->ia_size;
826 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700827 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
Deepa Dinamani95582b02018-05-08 19:36:02 -0700829 attrs.ia_atime = timespec64_to_timespec(attr->ia_atime);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700831 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
Deepa Dinamani95582b02018-05-08 19:36:02 -0700833 attrs.ia_mtime = timespec64_to_timespec(attr->ia_mtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700835 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
Deepa Dinamani95582b02018-05-08 19:36:02 -0700837 attrs.ia_ctime = timespec64_to_timespec(attr->ia_ctime);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
841 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700842 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
844 }
Al Viroc5322222010-06-06 20:42:10 -0400845 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700846 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700847 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700848 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400849 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700850 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700851 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Christoph Hellwig10257742010-06-04 11:30:02 +0200853 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200854 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200855 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200856
857 setattr_copy(inode, attr);
858 mark_inode_dirty(inode);
859 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800862static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 .permission = hostfs_permission,
864 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865};
866
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800867static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 .create = hostfs_create,
869 .lookup = hostfs_lookup,
870 .link = hostfs_link,
871 .unlink = hostfs_unlink,
872 .symlink = hostfs_symlink,
873 .mkdir = hostfs_mkdir,
874 .rmdir = hostfs_rmdir,
875 .mknod = hostfs_mknod,
Miklos Szeredi2773bf02016-09-27 11:03:58 +0200876 .rename = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 .permission = hostfs_permission,
878 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879};
880
Al Viro6b255392015-11-17 10:20:54 -0500881static const char *hostfs_get_link(struct dentry *dentry,
Al Virofceef392015-12-29 15:58:39 -0500882 struct inode *inode,
883 struct delayed_call *done)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
Al Viro6b255392015-11-17 10:20:54 -0500885 char *link;
886 if (!dentry)
887 return ERR_PTR(-ECHILD);
Al Virofceef392015-12-29 15:58:39 -0500888 link = kmalloc(PATH_MAX, GFP_KERNEL);
Al Virod0352d32010-06-06 21:51:16 -0400889 if (link) {
890 char *path = dentry_name(dentry);
891 int err = -ENOMEM;
892 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400893 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400894 if (err == PATH_MAX)
895 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400896 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400897 }
898 if (err < 0) {
Al Virofceef392015-12-29 15:58:39 -0500899 kfree(link);
Al Viro680baac2015-05-02 13:32:22 -0400900 return ERR_PTR(err);
Al Virod0352d32010-06-06 21:51:16 -0400901 }
902 } else {
Al Viro680baac2015-05-02 13:32:22 -0400903 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 }
Al Virod0352d32010-06-06 21:51:16 -0400905
Al Virofceef392015-12-29 15:58:39 -0500906 set_delayed_call(done, kfree_link, link);
907 return link;
Al Virod0352d32010-06-06 21:51:16 -0400908}
909
910static const struct inode_operations hostfs_link_iops = {
Al Viro6b255392015-11-17 10:20:54 -0500911 .get_link = hostfs_get_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912};
913
914static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
915{
916 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700917 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 int err;
919
920 sb->s_blocksize = 1024;
921 sb->s_blocksize_bits = 10;
922 sb->s_magic = HOSTFS_SUPER_MAGIC;
923 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400924 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700925 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800927 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700928 if (req_root == NULL)
929 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400932 sb->s_fs_info = host_root_path =
933 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700934 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 goto out;
936
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700937 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Al Viro52b209f2010-06-06 18:43:19 -0400939 root_inode = new_inode(sb);
940 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400941 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Al Viro4754b822010-06-06 20:33:12 -0400943 err = read_name(root_inode, host_root_path);
944 if (err)
945 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400946
Al Viro4754b822010-06-06 20:33:12 -0400947 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400948 char *name = follow_link(host_root_path);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300949 if (IS_ERR(name)) {
Al Viro52b209f2010-06-06 18:43:19 -0400950 err = PTR_ERR(name);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300951 goto out_put;
952 }
953 err = read_name(root_inode, name);
Al Viro52b209f2010-06-06 18:43:19 -0400954 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400955 if (err)
956 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500960 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700961 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500962 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Jeff Dikef1adc052007-05-08 00:23:18 -0700964 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Jeff Dikef1adc052007-05-08 00:23:18 -0700966out_put:
967 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700968out:
969 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970}
971
Al Viro3c26ff62010-07-25 11:46:36 +0400972static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700973 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400974 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
Al Viro3c26ff62010-07-25 11:46:36 +0400976 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977}
978
Al Viro601d2c32010-06-06 17:53:01 -0400979static void hostfs_kill_sb(struct super_block *s)
980{
981 kill_anon_super(s);
982 kfree(s->s_fs_info);
983}
984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985static struct file_system_type hostfs_type = {
986 .owner = THIS_MODULE,
987 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400988 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400989 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 .fs_flags = 0,
991};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700992MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994static int __init init_hostfs(void)
995{
Jeff Dikef1adc052007-05-08 00:23:18 -0700996 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997}
998
999static void __exit exit_hostfs(void)
1000{
1001 unregister_filesystem(&hostfs_type);
1002}
1003
1004module_init(init_hostfs)
1005module_exit(exit_hostfs)
1006MODULE_LICENSE("GPL");