blob: c60d886230efedeff9cbad1996bd6f5b4d3f662a [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
265 return 0;
266}
267
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800268static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400271 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800273 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274};
275
James Hogan9e443bc2013-11-14 21:15:13 +0000276static int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
278 void *dir;
279 char *name;
280 unsigned long long next, ino;
281 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100282 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Al Viroc5322222010-06-06 20:42:10 -0400284 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700285 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700286 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400288 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700289 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700290 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400291 next = ctx->pos;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100292 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400293 if (!dir_emit(ctx, name, len, ino, type))
294 break;
295 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 }
297 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700298 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299}
300
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100301static int hostfs_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
303 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400304 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400305 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400306 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700309 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700310 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Al Virof8ad8502010-06-06 23:49:18 -0400312 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Al Virof8ad8502010-06-06 23:49:18 -0400314retry:
315 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400317 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700319 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 r = 1;
321
Al Viroc5322222010-06-06 20:42:10 -0400322 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700323 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700324 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400327 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700328 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700329 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400330
Richard Weinberger69886e62015-02-27 22:55:20 +0100331 mutex_lock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400332 /* somebody else had handled it first? */
333 if ((mode & HOSTFS_I(ino)->mode) == mode) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100334 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Richard Weinbergeraf955652015-02-27 22:56:28 +0100335 close_file(&fd);
Al Virof8ad8502010-06-06 23:49:18 -0400336 return 0;
337 }
338 if ((mode | HOSTFS_I(ino)->mode) != mode) {
339 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100340 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400341 close_file(&fd);
342 goto retry;
343 }
344 if (HOSTFS_I(ino)->fd == -1) {
345 HOSTFS_I(ino)->fd = fd;
346 } else {
347 err = replace_file(fd, HOSTFS_I(ino)->fd);
348 close_file(&fd);
349 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100350 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400351 return err;
352 }
353 }
354 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100355 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Jeff Dikef1adc052007-05-08 00:23:18 -0700357 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358}
359
Richard Weinberger65984ff2013-08-04 17:23:51 +0000360static int hostfs_file_release(struct inode *inode, struct file *file)
361{
362 filemap_write_and_wait(inode->i_mapping);
363
364 return 0;
365}
366
James Hogan9e443bc2013-11-14 21:15:13 +0000367static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
368 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
Josef Bacik02c24a82011-07-16 20:44:56 -0400370 struct inode *inode = file->f_mapping->host;
371 int ret;
372
373 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
374 if (ret)
375 return ret;
376
377 mutex_lock(&inode->i_mutex);
378 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
379 mutex_unlock(&inode->i_mutex);
380
381 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382}
383
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800384static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 .llseek = generic_file_llseek,
Al Viroaad4f8b2014-04-02 14:33:16 -0400386 .read = new_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200387 .splice_read = generic_file_splice_read,
Al Viroaad4f8b2014-04-02 14:33:16 -0400388 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400389 .write_iter = generic_file_write_iter,
390 .write = new_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 .mmap = generic_file_mmap,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100392 .open = hostfs_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000393 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .fsync = hostfs_fsync,
395};
396
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800397static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 .llseek = generic_file_llseek,
Al Viro8e28bc72013-05-22 16:34:19 -0400399 .iterate = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 .read = generic_read_dir,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100401 .open = hostfs_open,
402 .fsync = hostfs_fsync,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403};
404
James Hogan9e443bc2013-11-14 21:15:13 +0000405static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
407 struct address_space *mapping = page->mapping;
408 struct inode *inode = mapping->host;
409 char *buffer;
410 unsigned long long base;
411 int count = PAGE_CACHE_SIZE;
412 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
413 int err;
414
415 if (page->index >= end_index)
416 count = inode->i_size & (PAGE_CACHE_SIZE-1);
417
418 buffer = kmap(page);
419 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
420
421 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700422 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 ClearPageUptodate(page);
424 goto out;
425 }
426
427 if (base > inode->i_size)
428 inode->i_size = base;
429
430 if (PageError(page))
431 ClearPageError(page);
432 err = 0;
433
434 out:
435 kunmap(page);
436
437 unlock_page(page);
438 return err;
439}
440
James Hogan9e443bc2013-11-14 21:15:13 +0000441static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
443 char *buffer;
444 long long start;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100445 int bytes_read, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 start = (long long) page->index << PAGE_CACHE_SHIFT;
448 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) {
452 ret = bytes_read;
Jeff Dike84b3db02007-10-16 01:27:13 -0700453 goto out;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Richard Weinberger41761dd2015-03-03 21:40:55 +0100456 memset(buffer + bytes_read, 0, PAGE_CACHE_SIZE - bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
458 flush_dcache_page(page);
459 SetPageUptodate(page);
460 if (PageError(page)) ClearPageError(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100461 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 out:
463 kunmap(page);
464 unlock_page(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100465 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466}
467
James Hogan9e443bc2013-11-14 21:15:13 +0000468static int hostfs_write_begin(struct file *file, struct address_space *mapping,
469 loff_t pos, unsigned len, unsigned flags,
470 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
Nick Pigginae361ff2007-10-16 01:25:17 -0700472 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Nick Piggin54566b22009-01-04 12:00:53 -0800474 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700475 if (!*pagep)
476 return -ENOMEM;
477 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478}
479
James Hogan9e443bc2013-11-14 21:15:13 +0000480static int hostfs_write_end(struct file *file, struct address_space *mapping,
481 loff_t pos, unsigned len, unsigned copied,
482 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700485 void *buffer;
486 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
487 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700490 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700492
493 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
494 SetPageUptodate(page);
495
Jeff Dike84b3db02007-10-16 01:27:13 -0700496 /*
497 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700498 * i_size against the last byte written.
499 */
500 if (err > 0 && (pos > inode->i_size))
501 inode->i_size = pos;
502 unlock_page(page);
503 page_cache_release(page);
504
Jeff Dikef1adc052007-05-08 00:23:18 -0700505 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700508static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 .writepage = hostfs_writepage,
510 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700511 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700512 .write_begin = hostfs_write_begin,
513 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514};
515
Al Viro4754b822010-06-06 20:33:12 -0400516static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
Al Viro4754b822010-06-06 20:33:12 -0400518 dev_t rdev;
519 struct hostfs_stat st;
520 int err = stat_file(name, &st, -1);
521 if (err)
522 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Al Viro5e2df282010-06-06 19:38:18 -0400524 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400525 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Al Viro4754b822010-06-06 20:33:12 -0400527 switch (st.mode & S_IFMT) {
528 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400529 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400530 break;
531 case S_IFDIR:
532 ino->i_op = &hostfs_dir_iops;
533 ino->i_fop = &hostfs_dir_fops;
534 break;
535 case S_IFCHR:
536 case S_IFBLK:
537 case S_IFIFO:
538 case S_IFSOCK:
539 init_special_inode(ino, st.mode & S_IFMT, rdev);
540 ino->i_op = &hostfs_iops;
541 break;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100542 case S_IFREG:
Al Viro4754b822010-06-06 20:33:12 -0400543 ino->i_op = &hostfs_iops;
544 ino->i_fop = &hostfs_file_fops;
545 ino->i_mapping->a_ops = &hostfs_aops;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100546 break;
547 default:
548 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
Al Viro4754b822010-06-06 20:33:12 -0400550
551 ino->i_ino = st.ino;
552 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200553 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800554 i_uid_write(ino, st.uid);
555 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400556 ino->i_atime = st.atime;
557 ino->i_mtime = st.mtime;
558 ino->i_ctime = st.ctime;
559 ino->i_size = st.size;
560 ino->i_blocks = st.blocks;
561 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
563
James Hogan9e443bc2013-11-14 21:15:13 +0000564static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
565 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
567 struct inode *inode;
568 char *name;
569 int error, fd;
570
David Howells0a370e52008-02-07 00:15:50 -0800571 inode = hostfs_iget(dir->i_sb);
572 if (IS_ERR(inode)) {
573 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700574 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400578 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700579 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 goto out_put;
581
582 fd = file_create(name,
583 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
584 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
585 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400586 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400588 else
Al Viro5e2df282010-06-06 19:38:18 -0400589 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Al Viroe9193052010-06-06 23:16:34 -0400591 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700592 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 goto out_put;
594
595 HOSTFS_I(inode)->fd = fd;
596 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
597 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700598 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
600 out_put:
601 iput(inode);
602 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700603 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604}
605
James Hogan9e443bc2013-11-14 21:15:13 +0000606static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
607 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609 struct inode *inode;
610 char *name;
611 int err;
612
David Howells0a370e52008-02-07 00:15:50 -0800613 inode = hostfs_iget(ino->i_sb);
614 if (IS_ERR(inode)) {
615 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400620 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700621 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 goto out_put;
623
624 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400625
Al Viroe9193052010-06-06 23:16:34 -0400626 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700627 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 iput(inode);
629 inode = NULL;
630 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700631 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 goto out_put;
633
634 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700635 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 out_put:
638 iput(inode);
639 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700640 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
James Hogan9e443bc2013-11-14 21:15:13 +0000643static int hostfs_link(struct dentry *to, struct inode *ino,
644 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
Jeff Dikef1adc052007-05-08 00:23:18 -0700646 char *from_name, *to_name;
647 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Al Viroc5322222010-06-06 20:42:10 -0400649 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700650 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400651 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700652 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400653 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700654 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700656 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400657 __putname(from_name);
658 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700659 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660}
661
James Hogan9e443bc2013-11-14 21:15:13 +0000662static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
664 char *file;
665 int err;
666
Jeff Dike84b3db02007-10-16 01:27:13 -0700667 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700668 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Al Virof8d7e182010-06-06 23:19:04 -0400670 if ((file = dentry_name(dentry)) == NULL)
671 return -ENOMEM;
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 err = unlink_file(file);
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_symlink(struct inode *ino, struct dentry *dentry,
679 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 char *file;
682 int err;
683
Al Viroc5322222010-06-06 20:42:10 -0400684 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700685 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400687 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689}
690
James Hogan9e443bc2013-11-14 21:15:13 +0000691static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
693 char *file;
694 int err;
695
Al Viroc5322222010-06-06 20:42:10 -0400696 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700697 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400699 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700700 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701}
702
James Hogan9e443bc2013-11-14 21:15:13 +0000703static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
705 char *file;
706 int err;
707
Al Viroc5322222010-06-06 20:42:10 -0400708 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700709 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400711 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700712 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713}
714
Al Viro1a67aaf2011-07-26 01:52:52 -0400715static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
717 struct inode *inode;
718 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800719 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
David Howells0a370e52008-02-07 00:15:50 -0800721 inode = hostfs_iget(dir->i_sb);
722 if (IS_ERR(inode)) {
723 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400728 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700729 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 goto out_put;
731
732 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800733 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400734 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 goto out_free;
736
737 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400738 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400739 if (err)
740 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700741 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 goto out_put;
743
744 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700745 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
747 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400748 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 out_put:
750 iput(inode);
751 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700752 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753}
754
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200755static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
756 struct inode *new_dir, struct dentry *new_dentry,
757 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200759 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 int err;
761
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200762 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
763 return -EINVAL;
764
765 old_name = dentry_name(old_dentry);
766 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700767 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200768 new_name = dentry_name(new_dentry);
769 if (new_name == NULL) {
770 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700771 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200773 if (!flags)
774 err = rename_file(old_name, new_name);
775 else
776 err = rename2_file(old_name, new_name, flags);
777
778 __putname(old_name);
779 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700780 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781}
782
James Hogan9e443bc2013-11-14 21:15:13 +0000783static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784{
785 char *name;
786 int r = 0, w = 0, x = 0, err;
787
Al Viro10556cb2011-06-20 19:28:19 -0400788 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100789 return -ECHILD;
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 if (desired & MAY_READ) r = 1;
792 if (desired & MAY_WRITE) w = 1;
793 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400794 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700795 if (name == NULL)
796 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700799 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 err = 0;
801 else
802 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400803 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700804 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400805 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 return err;
807}
808
James Hogan9e443bc2013-11-14 21:15:13 +0000809static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810{
Christoph Hellwig10257742010-06-04 11:30:02 +0200811 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 struct hostfs_iattr attrs;
813 char *name;
814 int err;
815
Christoph Hellwig10257742010-06-04 11:30:02 +0200816 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700817
Christoph Hellwig10257742010-06-04 11:30:02 +0200818 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 if (err)
820 return err;
821
Jeff Dike84b3db02007-10-16 01:27:13 -0700822 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 attr->ia_valid &= ~ATTR_SIZE;
824
825 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700826 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 attrs.ia_valid |= HOSTFS_ATTR_MODE;
828 attrs.ia_mode = attr->ia_mode;
829 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700830 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800832 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700834 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800836 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700838 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
840 attrs.ia_size = attr->ia_size;
841 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700842 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
844 attrs.ia_atime = attr->ia_atime;
845 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700846 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
848 attrs.ia_mtime = attr->ia_mtime;
849 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700850 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
852 attrs.ia_ctime = attr->ia_ctime;
853 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700854 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
856 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700857 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
859 }
Al Viroc5322222010-06-06 20:42:10 -0400860 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700861 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700862 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700863 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400864 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700865 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700866 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
Christoph Hellwig10257742010-06-04 11:30:02 +0200868 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200869 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200870 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200871
872 setattr_copy(inode, attr);
873 mark_inode_dirty(inode);
874 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875}
876
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800877static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 .permission = hostfs_permission,
879 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880};
881
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800882static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 .create = hostfs_create,
884 .lookup = hostfs_lookup,
885 .link = hostfs_link,
886 .unlink = hostfs_unlink,
887 .symlink = hostfs_symlink,
888 .mkdir = hostfs_mkdir,
889 .rmdir = hostfs_rmdir,
890 .mknod = hostfs_mknod,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200891 .rename2 = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 .permission = hostfs_permission,
893 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894};
895
Al Virod0352d32010-06-06 21:51:16 -0400896static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
Al Virod0352d32010-06-06 21:51:16 -0400898 char *link = __getname();
899 if (link) {
900 char *path = dentry_name(dentry);
901 int err = -ENOMEM;
902 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400903 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400904 if (err == PATH_MAX)
905 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400906 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400907 }
908 if (err < 0) {
909 __putname(link);
910 link = ERR_PTR(err);
911 }
912 } else {
913 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 }
Al Virod0352d32010-06-06 21:51:16 -0400915
916 nd_set_link(nd, link);
917 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918}
919
Al Virod0352d32010-06-06 21:51:16 -0400920static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
921{
922 char *s = nd_get_link(nd);
923 if (!IS_ERR(s))
924 __putname(s);
925}
926
927static const struct inode_operations hostfs_link_iops = {
928 .readlink = generic_readlink,
929 .follow_link = hostfs_follow_link,
930 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931};
932
933static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
934{
935 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700936 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 int err;
938
939 sb->s_blocksize = 1024;
940 sb->s_blocksize_bits = 10;
941 sb->s_magic = HOSTFS_SUPER_MAGIC;
942 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400943 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700944 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800946 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700947 if (req_root == NULL)
948 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400951 sb->s_fs_info = host_root_path =
952 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700953 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 goto out;
955
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700956 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Al Viro52b209f72010-06-06 18:43:19 -0400958 root_inode = new_inode(sb);
959 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400960 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Al Viro4754b822010-06-06 20:33:12 -0400962 err = read_name(root_inode, host_root_path);
963 if (err)
964 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400965
Al Viro4754b822010-06-06 20:33:12 -0400966 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400967 char *name = follow_link(host_root_path);
968 if (IS_ERR(name))
969 err = PTR_ERR(name);
970 else
971 err = read_name(root_inode, name);
972 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400973 if (err)
974 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500978 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700979 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500980 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Jeff Dikef1adc052007-05-08 00:23:18 -0700982 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Jeff Dikef1adc052007-05-08 00:23:18 -0700984out_put:
985 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700986out:
987 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988}
989
Al Viro3c26ff62010-07-25 11:46:36 +0400990static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700991 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400992 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993{
Al Viro3c26ff62010-07-25 11:46:36 +0400994 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995}
996
Al Viro601d2c32010-06-06 17:53:01 -0400997static void hostfs_kill_sb(struct super_block *s)
998{
999 kill_anon_super(s);
1000 kfree(s->s_fs_info);
1001}
1002
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003static struct file_system_type hostfs_type = {
1004 .owner = THIS_MODULE,
1005 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001006 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -04001007 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 .fs_flags = 0,
1009};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -07001010MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012static int __init init_hostfs(void)
1013{
Jeff Dikef1adc052007-05-08 00:23:18 -07001014 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015}
1016
1017static void __exit exit_hostfs(void)
1018{
1019 unregister_filesystem(&hostfs_type);
1020}
1021
1022module_init(init_hostfs)
1023module_exit(exit_hostfs)
1024MODULE_LICENSE("GPL");