blob: 3082a7e715dd9bafc5cf69c0c3dda1005a3f2e5b [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 }
108 if (p > name + len) {
109 char *s = name + len;
110 while ((*s++ = *p++) != '\0')
111 ;
112 }
113 return name;
114}
115
Al Viroc5322222010-06-06 20:42:10 -0400116static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
Al Viroe9193052010-06-06 23:16:34 -0400118 char *name = __getname();
119 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700120 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
James Hogan9dcc5e82013-03-27 10:47:12 +0000122 return __dentry_name(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123}
124
Al Viroc5322222010-06-06 20:42:10 -0400125static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126{
127 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100128 char *name;
129
130 dentry = d_find_alias(ino);
131 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400132 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Nick Pigginec2447c2011-01-07 17:49:29 +1100134 name = dentry_name(dentry);
135
136 dput(dentry);
137
138 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139}
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static char *follow_link(char *link)
142{
143 int len, n;
144 char *name, *resolved, *end;
145
146 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700147 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 n = -ENOMEM;
149 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700150 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 goto out;
152
WANG Congea7e7432008-11-19 15:36:46 -0800153 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700154 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 break;
156 len *= 2;
157 kfree(name);
158 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700159 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 goto out_free;
161
Jeff Dike84b3db02007-10-16 01:27:13 -0700162 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700163 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
165 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700166 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700167 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169 *(end + 1) = '\0';
170 len = strlen(link) + strlen(name) + 1;
171
172 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700173 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 n = -ENOMEM;
175 goto out_free;
176 }
177
178 sprintf(resolved, "%s%s", link, name);
179 kfree(name);
180 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700181 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183 out_free:
184 kfree(name);
185 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700186 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187}
188
David Howells0a370e52008-02-07 00:15:50 -0800189static struct inode *hostfs_iget(struct super_block *sb)
190{
Al Viro52b209f2010-06-06 18:43:19 -0400191 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800192 if (!inode)
193 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800194 return inode;
195}
196
James Hogan9e443bc2013-11-14 21:15:13 +0000197static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
Jeff Dike84b3db02007-10-16 01:27:13 -0700199 /*
200 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 * struct statfs still has 32-bit versions for most of these fields,
202 * so we convert them here
203 */
204 int err;
205 long long f_blocks;
206 long long f_bfree;
207 long long f_bavail;
208 long long f_files;
209 long long f_ffree;
210
Al Viro601d2c32010-06-06 17:53:01 -0400211 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
213 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700214 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700215 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700216 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 sf->f_blocks = f_blocks;
218 sf->f_bfree = f_bfree;
219 sf->f_bavail = f_bavail;
220 sf->f_files = f_files;
221 sf->f_ffree = f_ffree;
222 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700223 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224}
225
226static struct inode *hostfs_alloc_inode(struct super_block *sb)
227{
228 struct hostfs_inode_info *hi;
229
James Hogan371fdab2013-03-27 10:47:14 +0000230 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700231 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700232 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400233 hi->fd = -1;
James Hogan371fdab2013-03-27 10:47:14 +0000234 hi->mode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 inode_init_once(&hi->vfs_inode);
Richard Weinberger69886e62015-02-27 22:55:20 +0100236 mutex_init(&hi->open_mutex);
Jeff Dikef1adc052007-05-08 00:23:18 -0700237 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
239
Al Viroe971a6d2010-06-06 15:16:17 -0400240static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
Johannes Weiner91b0abe2014-04-03 14:47:49 -0700242 truncate_inode_pages_final(&inode->i_data);
Jan Karadbd57682012-05-03 14:48:02 +0200243 clear_inode(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700244 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 close_file(&HOSTFS_I(inode)->fd);
246 HOSTFS_I(inode)->fd = -1;
247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
249
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100250static void hostfs_i_callback(struct rcu_head *head)
251{
252 struct inode *inode = container_of(head, struct inode, i_rcu);
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100253 kfree(HOSTFS_I(inode));
254}
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256static void hostfs_destroy_inode(struct inode *inode)
257{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100258 call_rcu(&inode->i_rcu, hostfs_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259}
260
Al Viro34c80b12011-12-08 21:32:45 -0500261static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800262{
Al Viro34c80b12011-12-08 21:32:45 -0500263 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800264 size_t offset = strlen(root_ino) + 1;
265
266 if (strlen(root_path) > offset)
267 seq_printf(seq, ",%s", root_path + offset);
268
269 return 0;
270}
271
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800272static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400275 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800277 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278};
279
James Hogan9e443bc2013-11-14 21:15:13 +0000280static int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
282 void *dir;
283 char *name;
284 unsigned long long next, ino;
285 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100286 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Al Viroc5322222010-06-06 20:42:10 -0400288 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700289 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700290 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400292 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700293 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700294 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400295 next = ctx->pos;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100296 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400297 if (!dir_emit(ctx, name, len, ino, type))
298 break;
299 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700302 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303}
304
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100305static int hostfs_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
307 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400308 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400309 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400310 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700313 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700314 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Al Virof8ad8502010-06-06 23:49:18 -0400316 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Al Virof8ad8502010-06-06 23:49:18 -0400318retry:
319 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400321 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700323 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 r = 1;
325
Al Viroc5322222010-06-06 20:42:10 -0400326 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700327 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700328 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400331 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700332 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700333 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400334
Richard Weinberger69886e62015-02-27 22:55:20 +0100335 mutex_lock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400336 /* somebody else had handled it first? */
337 if ((mode & HOSTFS_I(ino)->mode) == mode) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100338 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Richard Weinbergeraf955652015-02-27 22:56:28 +0100339 close_file(&fd);
Al Virof8ad8502010-06-06 23:49:18 -0400340 return 0;
341 }
342 if ((mode | HOSTFS_I(ino)->mode) != mode) {
343 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100344 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400345 close_file(&fd);
346 goto retry;
347 }
348 if (HOSTFS_I(ino)->fd == -1) {
349 HOSTFS_I(ino)->fd = fd;
350 } else {
351 err = replace_file(fd, HOSTFS_I(ino)->fd);
352 close_file(&fd);
353 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100354 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400355 return err;
356 }
357 }
358 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100359 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Jeff Dikef1adc052007-05-08 00:23:18 -0700361 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
Richard Weinberger65984ff2013-08-04 17:23:51 +0000364static int hostfs_file_release(struct inode *inode, struct file *file)
365{
366 filemap_write_and_wait(inode->i_mapping);
367
368 return 0;
369}
370
James Hogan9e443bc2013-11-14 21:15:13 +0000371static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
372 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
Josef Bacik02c24a82011-07-16 20:44:56 -0400374 struct inode *inode = file->f_mapping->host;
375 int ret;
376
377 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
378 if (ret)
379 return ret;
380
381 mutex_lock(&inode->i_mutex);
382 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
383 mutex_unlock(&inode->i_mutex);
384
385 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386}
387
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800388static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 .llseek = generic_file_llseek,
Al Viroaad4f8b2014-04-02 14:33:16 -0400390 .read = new_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200391 .splice_read = generic_file_splice_read,
Al Viroaad4f8b2014-04-02 14:33:16 -0400392 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400393 .write_iter = generic_file_write_iter,
394 .write = new_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 .mmap = generic_file_mmap,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100396 .open = hostfs_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000397 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 .fsync = hostfs_fsync,
399};
400
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800401static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 .llseek = generic_file_llseek,
Al Viro8e28bc72013-05-22 16:34:19 -0400403 .iterate = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 .read = generic_read_dir,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100405 .open = hostfs_open,
406 .fsync = hostfs_fsync,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407};
408
James Hogan9e443bc2013-11-14 21:15:13 +0000409static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
411 struct address_space *mapping = page->mapping;
412 struct inode *inode = mapping->host;
413 char *buffer;
414 unsigned long long base;
415 int count = PAGE_CACHE_SIZE;
416 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
417 int err;
418
419 if (page->index >= end_index)
420 count = inode->i_size & (PAGE_CACHE_SIZE-1);
421
422 buffer = kmap(page);
423 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
424
425 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700426 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 ClearPageUptodate(page);
428 goto out;
429 }
430
431 if (base > inode->i_size)
432 inode->i_size = base;
433
434 if (PageError(page))
435 ClearPageError(page);
436 err = 0;
437
438 out:
439 kunmap(page);
440
441 unlock_page(page);
442 return err;
443}
444
James Hogan9e443bc2013-11-14 21:15:13 +0000445static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
447 char *buffer;
448 long long start;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100449 int bytes_read, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 start = (long long) page->index << PAGE_CACHE_SHIFT;
452 buffer = kmap(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100453 bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 PAGE_CACHE_SIZE);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100455 if (bytes_read < 0) {
456 ret = bytes_read;
Jeff Dike84b3db02007-10-16 01:27:13 -0700457 goto out;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
Richard Weinberger41761dd2015-03-03 21:40:55 +0100460 memset(buffer + bytes_read, 0, PAGE_CACHE_SIZE - bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
462 flush_dcache_page(page);
463 SetPageUptodate(page);
464 if (PageError(page)) ClearPageError(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100465 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 out:
467 kunmap(page);
468 unlock_page(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100469 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470}
471
James Hogan9e443bc2013-11-14 21:15:13 +0000472static int hostfs_write_begin(struct file *file, struct address_space *mapping,
473 loff_t pos, unsigned len, unsigned flags,
474 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
Nick Pigginae361ff2007-10-16 01:25:17 -0700476 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
Nick Piggin54566b22009-01-04 12:00:53 -0800478 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700479 if (!*pagep)
480 return -ENOMEM;
481 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482}
483
James Hogan9e443bc2013-11-14 21:15:13 +0000484static int hostfs_write_end(struct file *file, struct address_space *mapping,
485 loff_t pos, unsigned len, unsigned copied,
486 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700489 void *buffer;
490 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
491 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700494 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700496
497 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
498 SetPageUptodate(page);
499
Jeff Dike84b3db02007-10-16 01:27:13 -0700500 /*
501 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700502 * i_size against the last byte written.
503 */
504 if (err > 0 && (pos > inode->i_size))
505 inode->i_size = pos;
506 unlock_page(page);
507 page_cache_release(page);
508
Jeff Dikef1adc052007-05-08 00:23:18 -0700509 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510}
511
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700512static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 .writepage = hostfs_writepage,
514 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700515 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700516 .write_begin = hostfs_write_begin,
517 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518};
519
Al Viro4754b822010-06-06 20:33:12 -0400520static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
Al Viro4754b822010-06-06 20:33:12 -0400522 dev_t rdev;
523 struct hostfs_stat st;
524 int err = stat_file(name, &st, -1);
525 if (err)
526 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Al Viro5e2df282010-06-06 19:38:18 -0400528 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400529 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
Al Viro4754b822010-06-06 20:33:12 -0400531 switch (st.mode & S_IFMT) {
532 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400533 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400534 break;
535 case S_IFDIR:
536 ino->i_op = &hostfs_dir_iops;
537 ino->i_fop = &hostfs_dir_fops;
538 break;
539 case S_IFCHR:
540 case S_IFBLK:
541 case S_IFIFO:
542 case S_IFSOCK:
543 init_special_inode(ino, st.mode & S_IFMT, rdev);
544 ino->i_op = &hostfs_iops;
545 break;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100546 case S_IFREG:
Al Viro4754b822010-06-06 20:33:12 -0400547 ino->i_op = &hostfs_iops;
548 ino->i_fop = &hostfs_file_fops;
549 ino->i_mapping->a_ops = &hostfs_aops;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100550 break;
551 default:
552 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 }
Al Viro4754b822010-06-06 20:33:12 -0400554
555 ino->i_ino = st.ino;
556 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200557 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800558 i_uid_write(ino, st.uid);
559 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400560 ino->i_atime = st.atime;
561 ino->i_mtime = st.mtime;
562 ino->i_ctime = st.ctime;
563 ino->i_size = st.size;
564 ino->i_blocks = st.blocks;
565 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566}
567
James Hogan9e443bc2013-11-14 21:15:13 +0000568static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
569 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 struct inode *inode;
572 char *name;
573 int error, fd;
574
David Howells0a370e52008-02-07 00:15:50 -0800575 inode = hostfs_iget(dir->i_sb);
576 if (IS_ERR(inode)) {
577 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700578 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400582 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700583 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 goto out_put;
585
586 fd = file_create(name,
587 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
588 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
589 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400590 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400592 else
Al Viro5e2df282010-06-06 19:38:18 -0400593 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Al Viroe9193052010-06-06 23:16:34 -0400595 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700596 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 goto out_put;
598
599 HOSTFS_I(inode)->fd = fd;
600 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
601 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700602 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 out_put:
605 iput(inode);
606 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700607 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608}
609
James Hogan9e443bc2013-11-14 21:15:13 +0000610static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
611 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612{
613 struct inode *inode;
614 char *name;
615 int err;
616
David Howells0a370e52008-02-07 00:15:50 -0800617 inode = hostfs_iget(ino->i_sb);
618 if (IS_ERR(inode)) {
619 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400624 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700625 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 goto out_put;
627
628 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400629
Al Viroe9193052010-06-06 23:16:34 -0400630 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700631 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 iput(inode);
633 inode = NULL;
634 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700635 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 goto out_put;
637
638 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 out_put:
642 iput(inode);
643 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700644 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645}
646
James Hogan9e443bc2013-11-14 21:15:13 +0000647static int hostfs_link(struct dentry *to, struct inode *ino,
648 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649{
Jeff Dikef1adc052007-05-08 00:23:18 -0700650 char *from_name, *to_name;
651 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
Al Viroc5322222010-06-06 20:42:10 -0400653 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700654 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400655 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700656 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400657 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700658 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700660 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400661 __putname(from_name);
662 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700663 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664}
665
James Hogan9e443bc2013-11-14 21:15:13 +0000666static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
668 char *file;
669 int err;
670
Jeff Dike84b3db02007-10-16 01:27:13 -0700671 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700672 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Al Virof8d7e182010-06-06 23:19:04 -0400674 if ((file = dentry_name(dentry)) == NULL)
675 return -ENOMEM;
676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400678 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700679 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
James Hogan9e443bc2013-11-14 21:15:13 +0000682static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
683 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
685 char *file;
686 int err;
687
Al Viroc5322222010-06-06 20:42:10 -0400688 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700689 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400691 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700692 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693}
694
James Hogan9e443bc2013-11-14 21:15:13 +0000695static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
697 char *file;
698 int err;
699
Al Viroc5322222010-06-06 20:42:10 -0400700 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700701 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400703 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700704 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705}
706
James Hogan9e443bc2013-11-14 21:15:13 +0000707static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 char *file;
710 int err;
711
Al Viroc5322222010-06-06 20:42:10 -0400712 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700713 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400715 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700716 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717}
718
Al Viro1a67aaf2011-07-26 01:52:52 -0400719static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
721 struct inode *inode;
722 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800723 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
David Howells0a370e52008-02-07 00:15:50 -0800725 inode = hostfs_iget(dir->i_sb);
726 if (IS_ERR(inode)) {
727 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400732 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700733 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 goto out_put;
735
736 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800737 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400738 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 goto out_free;
740
741 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400742 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400743 if (err)
744 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700745 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 goto out_put;
747
748 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700749 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400752 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 out_put:
754 iput(inode);
755 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700756 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757}
758
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200759static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
760 struct inode *new_dir, struct dentry *new_dentry,
761 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200763 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 int err;
765
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200766 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
767 return -EINVAL;
768
769 old_name = dentry_name(old_dentry);
770 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700771 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200772 new_name = dentry_name(new_dentry);
773 if (new_name == NULL) {
774 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700775 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200777 if (!flags)
778 err = rename_file(old_name, new_name);
779 else
780 err = rename2_file(old_name, new_name, flags);
781
782 __putname(old_name);
783 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700784 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785}
786
James Hogan9e443bc2013-11-14 21:15:13 +0000787static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788{
789 char *name;
790 int r = 0, w = 0, x = 0, err;
791
Al Viro10556cb2011-06-20 19:28:19 -0400792 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100793 return -ECHILD;
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (desired & MAY_READ) r = 1;
796 if (desired & MAY_WRITE) w = 1;
797 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400798 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700799 if (name == NULL)
800 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700803 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 err = 0;
805 else
806 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400807 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700808 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400809 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return err;
811}
812
James Hogan9e443bc2013-11-14 21:15:13 +0000813static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
Christoph Hellwig10257742010-06-04 11:30:02 +0200815 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 struct hostfs_iattr attrs;
817 char *name;
818 int err;
819
Christoph Hellwig10257742010-06-04 11:30:02 +0200820 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700821
Christoph Hellwig10257742010-06-04 11:30:02 +0200822 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 if (err)
824 return err;
825
Jeff Dike84b3db02007-10-16 01:27:13 -0700826 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 attr->ia_valid &= ~ATTR_SIZE;
828
829 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700830 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 attrs.ia_valid |= HOSTFS_ATTR_MODE;
832 attrs.ia_mode = attr->ia_mode;
833 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700834 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800836 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700838 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800840 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700842 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
844 attrs.ia_size = attr->ia_size;
845 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700846 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
848 attrs.ia_atime = attr->ia_atime;
849 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700850 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
852 attrs.ia_mtime = attr->ia_mtime;
853 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700854 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
856 attrs.ia_ctime = attr->ia_ctime;
857 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700858 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
860 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700861 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
863 }
Al Viroc5322222010-06-06 20:42:10 -0400864 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700865 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700866 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700867 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400868 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700869 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700870 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Christoph Hellwig10257742010-06-04 11:30:02 +0200872 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200873 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200874 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200875
876 setattr_copy(inode, attr);
877 mark_inode_dirty(inode);
878 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879}
880
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800881static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 .permission = hostfs_permission,
883 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884};
885
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800886static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 .create = hostfs_create,
888 .lookup = hostfs_lookup,
889 .link = hostfs_link,
890 .unlink = hostfs_unlink,
891 .symlink = hostfs_symlink,
892 .mkdir = hostfs_mkdir,
893 .rmdir = hostfs_rmdir,
894 .mknod = hostfs_mknod,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200895 .rename2 = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 .permission = hostfs_permission,
897 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898};
899
Al Virod0352d32010-06-06 21:51:16 -0400900static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
Al Virod0352d32010-06-06 21:51:16 -0400902 char *link = __getname();
903 if (link) {
904 char *path = dentry_name(dentry);
905 int err = -ENOMEM;
906 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400907 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400908 if (err == PATH_MAX)
909 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400910 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400911 }
912 if (err < 0) {
913 __putname(link);
914 link = ERR_PTR(err);
915 }
916 } else {
917 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 }
Al Virod0352d32010-06-06 21:51:16 -0400919
920 nd_set_link(nd, link);
921 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922}
923
Al Virod0352d32010-06-06 21:51:16 -0400924static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
925{
926 char *s = nd_get_link(nd);
927 if (!IS_ERR(s))
928 __putname(s);
929}
930
931static const struct inode_operations hostfs_link_iops = {
932 .readlink = generic_readlink,
933 .follow_link = hostfs_follow_link,
934 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935};
936
937static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
938{
939 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700940 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 int err;
942
943 sb->s_blocksize = 1024;
944 sb->s_blocksize_bits = 10;
945 sb->s_magic = HOSTFS_SUPER_MAGIC;
946 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400947 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700948 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800950 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700951 if (req_root == NULL)
952 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400955 sb->s_fs_info = host_root_path =
956 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700957 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 goto out;
959
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700960 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Al Viro52b209f2010-06-06 18:43:19 -0400962 root_inode = new_inode(sb);
963 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400964 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Al Viro4754b822010-06-06 20:33:12 -0400966 err = read_name(root_inode, host_root_path);
967 if (err)
968 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400969
Al Viro4754b822010-06-06 20:33:12 -0400970 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400971 char *name = follow_link(host_root_path);
972 if (IS_ERR(name))
973 err = PTR_ERR(name);
974 else
975 err = read_name(root_inode, name);
976 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400977 if (err)
978 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500982 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700983 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500984 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Jeff Dikef1adc052007-05-08 00:23:18 -0700986 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Jeff Dikef1adc052007-05-08 00:23:18 -0700988out_put:
989 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700990out:
991 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992}
993
Al Viro3c26ff62010-07-25 11:46:36 +0400994static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700995 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400996 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
Al Viro3c26ff62010-07-25 11:46:36 +0400998 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999}
1000
Al Viro601d2c32010-06-06 17:53:01 -04001001static void hostfs_kill_sb(struct super_block *s)
1002{
1003 kill_anon_super(s);
1004 kfree(s->s_fs_info);
1005}
1006
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007static struct file_system_type hostfs_type = {
1008 .owner = THIS_MODULE,
1009 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001010 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -04001011 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 .fs_flags = 0,
1013};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -07001014MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016static int __init init_hostfs(void)
1017{
Jeff Dikef1adc052007-05-08 00:23:18 -07001018 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019}
1020
1021static void __exit exit_hostfs(void)
1022{
1023 unregister_filesystem(&hostfs_type);
1024}
1025
1026module_init(init_hostfs)
1027module_exit(exit_hostfs)
1028MODULE_LICENSE("GPL");