blob: 059597b23f677b0959d8264b83cf4c4a2cec34b7 [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 Viro52b209f72010-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
James Hogan371fdab2013-03-27 10:47:14 +0000226 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
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)
263 seq_printf(seq, ",%s", root_path + offset);
264
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
377 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
378 if (ret)
379 return ret;
380
381 mutex_lock(&inode->i_mutex);
382 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
383 mutex_unlock(&inode->i_mutex);
384
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 Viro8e28bc72013-05-22 16:34:19 -0400401 .iterate = 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 Weinbergeraf6aa1b2015-03-04 20:58:39 +0100412 loff_t base = page_offset(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 int count = PAGE_CACHE_SIZE;
414 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
415 int err;
416
417 if (page->index >= end_index)
418 count = inode->i_size & (PAGE_CACHE_SIZE-1);
419
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 Weinbergeraf6aa1b2015-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,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 PAGE_CACHE_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
Richard Weinberger41761dd2015-03-03 21:40:55 +0100458 memset(buffer + bytes_read, 0, PAGE_CACHE_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{
Nick Pigginae361ff2007-10-16 01:25:17 -0700474 pgoff_t index = pos >> PAGE_CACHE_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;
488 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
489 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
495 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
496 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);
505 page_cache_release(page);
506
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);
Al Viro4754b822010-06-06 20:33:12 -0400558 ino->i_atime = st.atime;
559 ino->i_mtime = st.mtime;
560 ino->i_ctime = st.ctime;
561 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);
613 if (IS_ERR(inode)) {
614 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400619 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700620 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 goto out_put;
622
623 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400624
Al Viroe9193052010-06-06 23:16:34 -0400625 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700626 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 iput(inode);
628 inode = NULL;
629 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700630 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 goto out_put;
632
633 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700634 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 out_put:
637 iput(inode);
638 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
James Hogan9e443bc2013-11-14 21:15:13 +0000642static int hostfs_link(struct dentry *to, struct inode *ino,
643 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
Jeff Dikef1adc052007-05-08 00:23:18 -0700645 char *from_name, *to_name;
646 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Al Viroc5322222010-06-06 20:42:10 -0400648 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400650 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700651 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400652 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700653 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400656 __putname(from_name);
657 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700658 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659}
660
James Hogan9e443bc2013-11-14 21:15:13 +0000661static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
663 char *file;
664 int err;
665
Jeff Dike84b3db02007-10-16 01:27:13 -0700666 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700667 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Al Virof8d7e182010-06-06 23:19:04 -0400669 if ((file = dentry_name(dentry)) == NULL)
670 return -ENOMEM;
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400673 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700674 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675}
676
James Hogan9e443bc2013-11-14 21:15:13 +0000677static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
678 const char *to)
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 = make_symlink(file, to);
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_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 err = do_mkdir(file, mode);
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
James Hogan9e443bc2013-11-14 21:15:13 +0000702static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 char *file;
705 int err;
706
Al Viroc5322222010-06-06 20:42:10 -0400707 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700708 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400710 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700711 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712}
713
Al Viro1a67aaf2011-07-26 01:52:52 -0400714static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
716 struct inode *inode;
717 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800718 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
David Howells0a370e52008-02-07 00:15:50 -0800720 inode = hostfs_iget(dir->i_sb);
721 if (IS_ERR(inode)) {
722 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400727 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700728 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 goto out_put;
730
731 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800732 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400733 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 goto out_free;
735
736 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400737 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400738 if (err)
739 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700740 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 goto out_put;
742
743 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700744 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
746 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400747 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 out_put:
749 iput(inode);
750 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700751 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200754static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
755 struct inode *new_dir, struct dentry *new_dentry,
756 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200758 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 int err;
760
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200761 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
762 return -EINVAL;
763
764 old_name = dentry_name(old_dentry);
765 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700766 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200767 new_name = dentry_name(new_dentry);
768 if (new_name == NULL) {
769 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700770 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200772 if (!flags)
773 err = rename_file(old_name, new_name);
774 else
775 err = rename2_file(old_name, new_name, flags);
776
777 __putname(old_name);
778 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700779 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780}
781
James Hogan9e443bc2013-11-14 21:15:13 +0000782static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783{
784 char *name;
785 int r = 0, w = 0, x = 0, err;
786
Al Viro10556cb2011-06-20 19:28:19 -0400787 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100788 return -ECHILD;
789
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if (desired & MAY_READ) r = 1;
791 if (desired & MAY_WRITE) w = 1;
792 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400793 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700794 if (name == NULL)
795 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700798 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 err = 0;
800 else
801 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400802 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700803 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400804 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 return err;
806}
807
James Hogan9e443bc2013-11-14 21:15:13 +0000808static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
David Howells2b0143b2015-03-17 22:25:59 +0000810 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 struct hostfs_iattr attrs;
812 char *name;
813 int err;
814
Christoph Hellwig10257742010-06-04 11:30:02 +0200815 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700816
Christoph Hellwig10257742010-06-04 11:30:02 +0200817 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 if (err)
819 return err;
820
Jeff Dike84b3db02007-10-16 01:27:13 -0700821 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 attr->ia_valid &= ~ATTR_SIZE;
823
824 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700825 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 attrs.ia_valid |= HOSTFS_ATTR_MODE;
827 attrs.ia_mode = attr->ia_mode;
828 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700829 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800831 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700833 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800835 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700837 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
839 attrs.ia_size = attr->ia_size;
840 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700841 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
843 attrs.ia_atime = attr->ia_atime;
844 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700845 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
847 attrs.ia_mtime = attr->ia_mtime;
848 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700849 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
851 attrs.ia_ctime = attr->ia_ctime;
852 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700853 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
855 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700856 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
858 }
Al Viroc5322222010-06-06 20:42:10 -0400859 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700860 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700861 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700862 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400863 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700864 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700865 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Christoph Hellwig10257742010-06-04 11:30:02 +0200867 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200868 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200869 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200870
871 setattr_copy(inode, attr);
872 mark_inode_dirty(inode);
873 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874}
875
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800876static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 .permission = hostfs_permission,
878 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879};
880
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800881static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 .create = hostfs_create,
883 .lookup = hostfs_lookup,
884 .link = hostfs_link,
885 .unlink = hostfs_unlink,
886 .symlink = hostfs_symlink,
887 .mkdir = hostfs_mkdir,
888 .rmdir = hostfs_rmdir,
889 .mknod = hostfs_mknod,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200890 .rename2 = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 .permission = hostfs_permission,
892 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893};
894
Al Viro6e771372015-05-02 13:37:52 -0400895static const char *hostfs_follow_link(struct dentry *dentry, void **cookie)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
Al Virod0352d32010-06-06 21:51:16 -0400897 char *link = __getname();
898 if (link) {
899 char *path = dentry_name(dentry);
900 int err = -ENOMEM;
901 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400902 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400903 if (err == PATH_MAX)
904 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400905 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400906 }
907 if (err < 0) {
908 __putname(link);
Al Viro680baac2015-05-02 13:32:22 -0400909 return ERR_PTR(err);
Al Virod0352d32010-06-06 21:51:16 -0400910 }
911 } else {
Al Viro680baac2015-05-02 13:32:22 -0400912 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 }
Al Virod0352d32010-06-06 21:51:16 -0400914
Al Viro680baac2015-05-02 13:32:22 -0400915 return *cookie = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916}
917
Al Viro5f2c4172015-05-07 11:14:26 -0400918static void hostfs_put_link(struct inode *unused, void *cookie)
Al Virod0352d32010-06-06 21:51:16 -0400919{
Al Viro680baac2015-05-02 13:32:22 -0400920 __putname(cookie);
Al Virod0352d32010-06-06 21:51:16 -0400921}
922
923static const struct inode_operations hostfs_link_iops = {
924 .readlink = generic_readlink,
925 .follow_link = hostfs_follow_link,
926 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927};
928
929static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
930{
931 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700932 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 int err;
934
935 sb->s_blocksize = 1024;
936 sb->s_blocksize_bits = 10;
937 sb->s_magic = HOSTFS_SUPER_MAGIC;
938 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400939 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700940 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800942 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700943 if (req_root == NULL)
944 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400947 sb->s_fs_info = host_root_path =
948 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700949 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 goto out;
951
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700952 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
Al Viro52b209f72010-06-06 18:43:19 -0400954 root_inode = new_inode(sb);
955 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400956 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Al Viro4754b822010-06-06 20:33:12 -0400958 err = read_name(root_inode, host_root_path);
959 if (err)
960 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400961
Al Viro4754b822010-06-06 20:33:12 -0400962 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400963 char *name = follow_link(host_root_path);
964 if (IS_ERR(name))
965 err = PTR_ERR(name);
966 else
967 err = read_name(root_inode, name);
968 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400969 if (err)
970 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500974 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700975 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500976 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Jeff Dikef1adc052007-05-08 00:23:18 -0700978 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Jeff Dikef1adc052007-05-08 00:23:18 -0700980out_put:
981 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700982out:
983 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984}
985
Al Viro3c26ff62010-07-25 11:46:36 +0400986static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700987 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400988 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989{
Al Viro3c26ff62010-07-25 11:46:36 +0400990 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
Al Viro601d2c32010-06-06 17:53:01 -0400993static void hostfs_kill_sb(struct super_block *s)
994{
995 kill_anon_super(s);
996 kfree(s->s_fs_info);
997}
998
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999static struct file_system_type hostfs_type = {
1000 .owner = THIS_MODULE,
1001 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001002 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -04001003 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 .fs_flags = 0,
1005};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -07001006MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008static int __init init_hostfs(void)
1009{
Jeff Dikef1adc052007-05-08 00:23:18 -07001010 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011}
1012
1013static void __exit exit_hostfs(void)
1014{
1015 unregister_filesystem(&hostfs_type);
1016}
1017
1018module_init(init_hostfs)
1019module_exit(exit_hostfs)
1020MODULE_LICENSE("GPL");