blob: 06b3e3f47c0ee4e714f37a5a10d0425035893586 [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;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100295 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400296 if (!dir_emit(ctx, name, len, ino, type))
297 break;
298 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700301 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302}
303
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100304static int hostfs_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
306 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400307 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400308 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400309 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700312 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700313 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Al Virof8ad8502010-06-06 23:49:18 -0400315 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Al Virof8ad8502010-06-06 23:49:18 -0400317retry:
318 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400320 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700322 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 r = 1;
324
Al Viroc5322222010-06-06 20:42:10 -0400325 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700326 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700327 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400330 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700331 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700332 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400333
Richard Weinberger69886e62015-02-27 22:55:20 +0100334 mutex_lock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400335 /* somebody else had handled it first? */
336 if ((mode & HOSTFS_I(ino)->mode) == mode) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100337 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Richard Weinbergeraf955652015-02-27 22:56:28 +0100338 close_file(&fd);
Al Virof8ad8502010-06-06 23:49:18 -0400339 return 0;
340 }
341 if ((mode | HOSTFS_I(ino)->mode) != mode) {
342 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100343 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400344 close_file(&fd);
345 goto retry;
346 }
347 if (HOSTFS_I(ino)->fd == -1) {
348 HOSTFS_I(ino)->fd = fd;
349 } else {
350 err = replace_file(fd, HOSTFS_I(ino)->fd);
351 close_file(&fd);
352 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100353 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400354 return err;
355 }
356 }
357 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100358 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Jeff Dikef1adc052007-05-08 00:23:18 -0700360 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361}
362
Richard Weinberger65984ff2013-08-04 17:23:51 +0000363static int hostfs_file_release(struct inode *inode, struct file *file)
364{
365 filemap_write_and_wait(inode->i_mapping);
366
367 return 0;
368}
369
James Hogan9e443bc2013-11-14 21:15:13 +0000370static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
371 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
Josef Bacik02c24a82011-07-16 20:44:56 -0400373 struct inode *inode = file->f_mapping->host;
374 int ret;
375
376 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
377 if (ret)
378 return ret;
379
380 mutex_lock(&inode->i_mutex);
381 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
382 mutex_unlock(&inode->i_mutex);
383
384 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800387static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 .llseek = generic_file_llseek,
Al Viroaad4f8b2014-04-02 14:33:16 -0400389 .read = new_sync_read,
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,
393 .write = new_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .mmap = generic_file_mmap,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100395 .open = hostfs_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000396 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 .fsync = hostfs_fsync,
398};
399
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800400static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 .llseek = generic_file_llseek,
Al Viro8e28bc72013-05-22 16:34:19 -0400402 .iterate = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 .read = generic_read_dir,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100404 .open = hostfs_open,
405 .fsync = hostfs_fsync,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406};
407
James Hogan9e443bc2013-11-14 21:15:13 +0000408static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
410 struct address_space *mapping = page->mapping;
411 struct inode *inode = mapping->host;
412 char *buffer;
413 unsigned long long base;
414 int count = PAGE_CACHE_SIZE;
415 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
416 int err;
417
418 if (page->index >= end_index)
419 count = inode->i_size & (PAGE_CACHE_SIZE-1);
420
421 buffer = kmap(page);
422 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
423
424 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700425 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 ClearPageUptodate(page);
427 goto out;
428 }
429
430 if (base > inode->i_size)
431 inode->i_size = base;
432
433 if (PageError(page))
434 ClearPageError(page);
435 err = 0;
436
437 out:
438 kunmap(page);
439
440 unlock_page(page);
441 return err;
442}
443
James Hogan9e443bc2013-11-14 21:15:13 +0000444static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
446 char *buffer;
447 long long start;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100448 int bytes_read, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450 start = (long long) page->index << PAGE_CACHE_SHIFT;
451 buffer = kmap(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100452 bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 PAGE_CACHE_SIZE);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100454 if (bytes_read < 0) {
455 ret = bytes_read;
Jeff Dike84b3db02007-10-16 01:27:13 -0700456 goto out;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Richard Weinberger41761dd2015-03-03 21:40:55 +0100459 memset(buffer + bytes_read, 0, PAGE_CACHE_SIZE - bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 flush_dcache_page(page);
462 SetPageUptodate(page);
463 if (PageError(page)) ClearPageError(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100464 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 out:
466 kunmap(page);
467 unlock_page(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100468 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469}
470
James Hogan9e443bc2013-11-14 21:15:13 +0000471static int hostfs_write_begin(struct file *file, struct address_space *mapping,
472 loff_t pos, unsigned len, unsigned flags,
473 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
Nick Pigginae361ff2007-10-16 01:25:17 -0700475 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Nick Piggin54566b22009-01-04 12:00:53 -0800477 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700478 if (!*pagep)
479 return -ENOMEM;
480 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481}
482
James Hogan9e443bc2013-11-14 21:15:13 +0000483static int hostfs_write_end(struct file *file, struct address_space *mapping,
484 loff_t pos, unsigned len, unsigned copied,
485 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700488 void *buffer;
489 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
490 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700493 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700495
496 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
497 SetPageUptodate(page);
498
Jeff Dike84b3db02007-10-16 01:27:13 -0700499 /*
500 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700501 * i_size against the last byte written.
502 */
503 if (err > 0 && (pos > inode->i_size))
504 inode->i_size = pos;
505 unlock_page(page);
506 page_cache_release(page);
507
Jeff Dikef1adc052007-05-08 00:23:18 -0700508 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509}
510
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700511static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 .writepage = hostfs_writepage,
513 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700514 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700515 .write_begin = hostfs_write_begin,
516 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517};
518
Al Viro4754b822010-06-06 20:33:12 -0400519static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520{
Al Viro4754b822010-06-06 20:33:12 -0400521 dev_t rdev;
522 struct hostfs_stat st;
523 int err = stat_file(name, &st, -1);
524 if (err)
525 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Al Viro5e2df282010-06-06 19:38:18 -0400527 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400528 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Al Viro4754b822010-06-06 20:33:12 -0400530 switch (st.mode & S_IFMT) {
531 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400532 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400533 break;
534 case S_IFDIR:
535 ino->i_op = &hostfs_dir_iops;
536 ino->i_fop = &hostfs_dir_fops;
537 break;
538 case S_IFCHR:
539 case S_IFBLK:
540 case S_IFIFO:
541 case S_IFSOCK:
542 init_special_inode(ino, st.mode & S_IFMT, rdev);
543 ino->i_op = &hostfs_iops;
544 break;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100545 case S_IFREG:
Al Viro4754b822010-06-06 20:33:12 -0400546 ino->i_op = &hostfs_iops;
547 ino->i_fop = &hostfs_file_fops;
548 ino->i_mapping->a_ops = &hostfs_aops;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100549 break;
550 default:
551 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 }
Al Viro4754b822010-06-06 20:33:12 -0400553
554 ino->i_ino = st.ino;
555 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200556 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800557 i_uid_write(ino, st.uid);
558 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400559 ino->i_atime = st.atime;
560 ino->i_mtime = st.mtime;
561 ino->i_ctime = st.ctime;
562 ino->i_size = st.size;
563 ino->i_blocks = st.blocks;
564 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565}
566
James Hogan9e443bc2013-11-14 21:15:13 +0000567static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
568 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
570 struct inode *inode;
571 char *name;
572 int error, fd;
573
David Howells0a370e52008-02-07 00:15:50 -0800574 inode = hostfs_iget(dir->i_sb);
575 if (IS_ERR(inode)) {
576 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700577 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400581 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700582 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 goto out_put;
584
585 fd = file_create(name,
586 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
587 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
588 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400589 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400591 else
Al Viro5e2df282010-06-06 19:38:18 -0400592 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Al Viroe9193052010-06-06 23:16:34 -0400594 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700595 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 goto out_put;
597
598 HOSTFS_I(inode)->fd = fd;
599 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
600 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700601 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603 out_put:
604 iput(inode);
605 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700606 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607}
608
James Hogan9e443bc2013-11-14 21:15:13 +0000609static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
610 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
612 struct inode *inode;
613 char *name;
614 int err;
615
David Howells0a370e52008-02-07 00:15:50 -0800616 inode = hostfs_iget(ino->i_sb);
617 if (IS_ERR(inode)) {
618 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400623 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700624 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 goto out_put;
626
627 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400628
Al Viroe9193052010-06-06 23:16:34 -0400629 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700630 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 iput(inode);
632 inode = NULL;
633 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700634 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 goto out_put;
636
637 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700638 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640 out_put:
641 iput(inode);
642 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700643 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644}
645
James Hogan9e443bc2013-11-14 21:15:13 +0000646static int hostfs_link(struct dentry *to, struct inode *ino,
647 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 char *from_name, *to_name;
650 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Al Viroc5322222010-06-06 20:42:10 -0400652 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700653 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400654 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700655 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400656 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700657 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700659 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400660 __putname(from_name);
661 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700662 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663}
664
James Hogan9e443bc2013-11-14 21:15:13 +0000665static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
667 char *file;
668 int err;
669
Jeff Dike84b3db02007-10-16 01:27:13 -0700670 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700671 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
Al Virof8d7e182010-06-06 23:19:04 -0400673 if ((file = dentry_name(dentry)) == NULL)
674 return -ENOMEM;
675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400677 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700678 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679}
680
James Hogan9e443bc2013-11-14 21:15:13 +0000681static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
682 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
684 char *file;
685 int err;
686
Al Viroc5322222010-06-06 20:42:10 -0400687 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400690 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700691 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692}
693
James Hogan9e443bc2013-11-14 21:15:13 +0000694static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
696 char *file;
697 int err;
698
Al Viroc5322222010-06-06 20:42:10 -0400699 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700700 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400702 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700703 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704}
705
James Hogan9e443bc2013-11-14 21:15:13 +0000706static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
708 char *file;
709 int err;
710
Al Viroc5322222010-06-06 20:42:10 -0400711 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700712 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400714 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700715 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716}
717
Al Viro1a67aaf2011-07-26 01:52:52 -0400718static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
720 struct inode *inode;
721 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800722 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
David Howells0a370e52008-02-07 00:15:50 -0800724 inode = hostfs_iget(dir->i_sb);
725 if (IS_ERR(inode)) {
726 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400731 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700732 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 goto out_put;
734
735 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800736 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400737 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 goto out_free;
739
740 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400741 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400742 if (err)
743 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700744 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 goto out_put;
746
747 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700748 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400751 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 out_put:
753 iput(inode);
754 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700755 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756}
757
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200758static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
759 struct inode *new_dir, struct dentry *new_dentry,
760 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200762 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 int err;
764
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200765 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
766 return -EINVAL;
767
768 old_name = dentry_name(old_dentry);
769 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700770 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200771 new_name = dentry_name(new_dentry);
772 if (new_name == NULL) {
773 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700774 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200776 if (!flags)
777 err = rename_file(old_name, new_name);
778 else
779 err = rename2_file(old_name, new_name, flags);
780
781 __putname(old_name);
782 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700783 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784}
785
James Hogan9e443bc2013-11-14 21:15:13 +0000786static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787{
788 char *name;
789 int r = 0, w = 0, x = 0, err;
790
Al Viro10556cb2011-06-20 19:28:19 -0400791 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100792 return -ECHILD;
793
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 if (desired & MAY_READ) r = 1;
795 if (desired & MAY_WRITE) w = 1;
796 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400797 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700798 if (name == NULL)
799 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700802 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 err = 0;
804 else
805 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400806 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700807 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400808 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 return err;
810}
811
James Hogan9e443bc2013-11-14 21:15:13 +0000812static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
Christoph Hellwig10257742010-06-04 11:30:02 +0200814 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 struct hostfs_iattr attrs;
816 char *name;
817 int err;
818
Christoph Hellwig10257742010-06-04 11:30:02 +0200819 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700820
Christoph Hellwig10257742010-06-04 11:30:02 +0200821 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 if (err)
823 return err;
824
Jeff Dike84b3db02007-10-16 01:27:13 -0700825 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 attr->ia_valid &= ~ATTR_SIZE;
827
828 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700829 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 attrs.ia_valid |= HOSTFS_ATTR_MODE;
831 attrs.ia_mode = attr->ia_mode;
832 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700833 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800835 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700837 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800839 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700841 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
843 attrs.ia_size = attr->ia_size;
844 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700845 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
847 attrs.ia_atime = attr->ia_atime;
848 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700849 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
851 attrs.ia_mtime = attr->ia_mtime;
852 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700853 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
855 attrs.ia_ctime = attr->ia_ctime;
856 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700857 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
859 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700860 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
862 }
Al Viroc5322222010-06-06 20:42:10 -0400863 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700864 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700865 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700866 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400867 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700868 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700869 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Christoph Hellwig10257742010-06-04 11:30:02 +0200871 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200872 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200873 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200874
875 setattr_copy(inode, attr);
876 mark_inode_dirty(inode);
877 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878}
879
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800880static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 .permission = hostfs_permission,
882 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883};
884
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800885static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 .create = hostfs_create,
887 .lookup = hostfs_lookup,
888 .link = hostfs_link,
889 .unlink = hostfs_unlink,
890 .symlink = hostfs_symlink,
891 .mkdir = hostfs_mkdir,
892 .rmdir = hostfs_rmdir,
893 .mknod = hostfs_mknod,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200894 .rename2 = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 .permission = hostfs_permission,
896 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897};
898
Al Virod0352d32010-06-06 21:51:16 -0400899static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
Al Virod0352d32010-06-06 21:51:16 -0400901 char *link = __getname();
902 if (link) {
903 char *path = dentry_name(dentry);
904 int err = -ENOMEM;
905 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400906 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400907 if (err == PATH_MAX)
908 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400909 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400910 }
911 if (err < 0) {
912 __putname(link);
913 link = ERR_PTR(err);
914 }
915 } else {
916 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 }
Al Virod0352d32010-06-06 21:51:16 -0400918
919 nd_set_link(nd, link);
920 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921}
922
Al Virod0352d32010-06-06 21:51:16 -0400923static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
924{
925 char *s = nd_get_link(nd);
926 if (!IS_ERR(s))
927 __putname(s);
928}
929
930static const struct inode_operations hostfs_link_iops = {
931 .readlink = generic_readlink,
932 .follow_link = hostfs_follow_link,
933 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934};
935
936static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
937{
938 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700939 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 int err;
941
942 sb->s_blocksize = 1024;
943 sb->s_blocksize_bits = 10;
944 sb->s_magic = HOSTFS_SUPER_MAGIC;
945 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400946 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700947 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800949 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700950 if (req_root == NULL)
951 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400954 sb->s_fs_info = host_root_path =
955 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700956 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 goto out;
958
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700959 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Al Viro52b209f72010-06-06 18:43:19 -0400961 root_inode = new_inode(sb);
962 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400963 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Al Viro4754b822010-06-06 20:33:12 -0400965 err = read_name(root_inode, host_root_path);
966 if (err)
967 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400968
Al Viro4754b822010-06-06 20:33:12 -0400969 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400970 char *name = follow_link(host_root_path);
971 if (IS_ERR(name))
972 err = PTR_ERR(name);
973 else
974 err = read_name(root_inode, name);
975 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400976 if (err)
977 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500981 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700982 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500983 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Jeff Dikef1adc052007-05-08 00:23:18 -0700985 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Jeff Dikef1adc052007-05-08 00:23:18 -0700987out_put:
988 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700989out:
990 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
Al Viro3c26ff62010-07-25 11:46:36 +0400993static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700994 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400995 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996{
Al Viro3c26ff62010-07-25 11:46:36 +0400997 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998}
999
Al Viro601d2c32010-06-06 17:53:01 -04001000static void hostfs_kill_sb(struct super_block *s)
1001{
1002 kill_anon_super(s);
1003 kfree(s->s_fs_info);
1004}
1005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006static struct file_system_type hostfs_type = {
1007 .owner = THIS_MODULE,
1008 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001009 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -04001010 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 .fs_flags = 0,
1012};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -07001013MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015static int __init init_hostfs(void)
1016{
Jeff Dikef1adc052007-05-08 00:23:18 -07001017 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018}
1019
1020static void __exit exit_hostfs(void)
1021{
1022 unregister_filesystem(&hostfs_type);
1023}
1024
1025module_init(init_hostfs)
1026module_exit(exit_hostfs)
1027MODULE_LICENSE("GPL");