blob: 104d58d2c78c7c57482fe24e2637afd6106319bd [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 }
Al Viro850a4962010-08-18 06:18:57 -040096 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040097 if (len > p - name) {
98 __putname(name);
99 return NULL;
100 }
101 if (p > name + len) {
102 char *s = name + len;
103 while ((*s++ = *p++) != '\0')
104 ;
105 }
106 return name;
107}
108
Al Viroc5322222010-06-06 20:42:10 -0400109static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110{
Al Viroe9193052010-06-06 23:16:34 -0400111 char *name = __getname();
112 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700113 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
James Hogan9dcc5e82013-03-27 10:47:12 +0000115 return __dentry_name(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116}
117
Al Viroc5322222010-06-06 20:42:10 -0400118static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119{
120 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100121 char *name;
122
123 dentry = d_find_alias(ino);
124 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400125 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Nick Pigginec2447c2011-01-07 17:49:29 +1100127 name = dentry_name(dentry);
128
129 dput(dentry);
130
131 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132}
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134static char *follow_link(char *link)
135{
136 int len, n;
137 char *name, *resolved, *end;
138
139 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700140 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 n = -ENOMEM;
142 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700143 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 goto out;
145
WANG Congea7e7432008-11-19 15:36:46 -0800146 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700147 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 break;
149 len *= 2;
150 kfree(name);
151 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700152 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 goto out_free;
154
Jeff Dike84b3db02007-10-16 01:27:13 -0700155 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700156 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
158 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700159 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700160 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162 *(end + 1) = '\0';
163 len = strlen(link) + strlen(name) + 1;
164
165 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700166 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 n = -ENOMEM;
168 goto out_free;
169 }
170
171 sprintf(resolved, "%s%s", link, name);
172 kfree(name);
173 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700174 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
176 out_free:
177 kfree(name);
178 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700179 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180}
181
David Howells0a370e52008-02-07 00:15:50 -0800182static struct inode *hostfs_iget(struct super_block *sb)
183{
Al Viro52b209f72010-06-06 18:43:19 -0400184 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800185 if (!inode)
186 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800187 return inode;
188}
189
James Hogan9e443bc2013-11-14 21:15:13 +0000190static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191{
Jeff Dike84b3db02007-10-16 01:27:13 -0700192 /*
193 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 * struct statfs still has 32-bit versions for most of these fields,
195 * so we convert them here
196 */
197 int err;
198 long long f_blocks;
199 long long f_bfree;
200 long long f_bavail;
201 long long f_files;
202 long long f_ffree;
203
Al Viro601d2c32010-06-06 17:53:01 -0400204 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
206 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700207 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700208 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700209 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 sf->f_blocks = f_blocks;
211 sf->f_bfree = f_bfree;
212 sf->f_bavail = f_bavail;
213 sf->f_files = f_files;
214 sf->f_ffree = f_ffree;
215 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700216 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217}
218
219static struct inode *hostfs_alloc_inode(struct super_block *sb)
220{
221 struct hostfs_inode_info *hi;
222
James Hogan371fdab2013-03-27 10:47:14 +0000223 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700224 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700225 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400226 hi->fd = -1;
James Hogan371fdab2013-03-27 10:47:14 +0000227 hi->mode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 inode_init_once(&hi->vfs_inode);
Richard Weinberger69886e62015-02-27 22:55:20 +0100229 mutex_init(&hi->open_mutex);
Jeff Dikef1adc052007-05-08 00:23:18 -0700230 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231}
232
Al Viroe971a6d2010-06-06 15:16:17 -0400233static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
Johannes Weiner91b0abe2014-04-03 14:47:49 -0700235 truncate_inode_pages_final(&inode->i_data);
Jan Karadbd57682012-05-03 14:48:02 +0200236 clear_inode(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700237 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 close_file(&HOSTFS_I(inode)->fd);
239 HOSTFS_I(inode)->fd = -1;
240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241}
242
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100243static void hostfs_i_callback(struct rcu_head *head)
244{
245 struct inode *inode = container_of(head, struct inode, i_rcu);
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100246 kfree(HOSTFS_I(inode));
247}
248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249static void hostfs_destroy_inode(struct inode *inode)
250{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100251 call_rcu(&inode->i_rcu, hostfs_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252}
253
Al Viro34c80b12011-12-08 21:32:45 -0500254static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800255{
Al Viro34c80b12011-12-08 21:32:45 -0500256 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800257 size_t offset = strlen(root_ino) + 1;
258
259 if (strlen(root_path) > offset)
260 seq_printf(seq, ",%s", root_path + offset);
261
262 return 0;
263}
264
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800265static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400268 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800270 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271};
272
James Hogan9e443bc2013-11-14 21:15:13 +0000273static int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
275 void *dir;
276 char *name;
277 unsigned long long next, ino;
278 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100279 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Al Viroc5322222010-06-06 20:42:10 -0400281 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700282 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700283 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400285 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700286 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700287 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400288 next = ctx->pos;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100289 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400290 if (!dir_emit(ctx, name, len, ino, type))
291 break;
292 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 }
294 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700295 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
James Hogan9e443bc2013-11-14 21:15:13 +0000298static int hostfs_file_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400301 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400302 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400303 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700306 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700307 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Al Virof8ad8502010-06-06 23:49:18 -0400309 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Al Virof8ad8502010-06-06 23:49:18 -0400311retry:
312 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400314 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700316 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 r = 1;
318
Al Viroc5322222010-06-06 20:42:10 -0400319 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700320 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700321 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400324 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700325 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700326 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400327
Richard Weinberger69886e62015-02-27 22:55:20 +0100328 mutex_lock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400329 /* somebody else had handled it first? */
330 if ((mode & HOSTFS_I(ino)->mode) == mode) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100331 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400332 return 0;
333 }
334 if ((mode | HOSTFS_I(ino)->mode) != mode) {
335 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100336 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400337 close_file(&fd);
338 goto retry;
339 }
340 if (HOSTFS_I(ino)->fd == -1) {
341 HOSTFS_I(ino)->fd = fd;
342 } else {
343 err = replace_file(fd, HOSTFS_I(ino)->fd);
344 close_file(&fd);
345 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100346 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400347 return err;
348 }
349 }
350 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100351 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Jeff Dikef1adc052007-05-08 00:23:18 -0700353 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354}
355
Richard Weinberger65984ff2013-08-04 17:23:51 +0000356static int hostfs_file_release(struct inode *inode, struct file *file)
357{
358 filemap_write_and_wait(inode->i_mapping);
359
360 return 0;
361}
362
James Hogan9e443bc2013-11-14 21:15:13 +0000363static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
364 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Josef Bacik02c24a82011-07-16 20:44:56 -0400366 struct inode *inode = file->f_mapping->host;
367 int ret;
368
369 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
370 if (ret)
371 return ret;
372
373 mutex_lock(&inode->i_mutex);
374 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
375 mutex_unlock(&inode->i_mutex);
376
377 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378}
379
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800380static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 .llseek = generic_file_llseek,
Al Viroaad4f8b2014-04-02 14:33:16 -0400382 .read = new_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200383 .splice_read = generic_file_splice_read,
Al Viroaad4f8b2014-04-02 14:33:16 -0400384 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400385 .write_iter = generic_file_write_iter,
386 .write = new_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 .mmap = generic_file_mmap,
388 .open = hostfs_file_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000389 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 .fsync = hostfs_fsync,
391};
392
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800393static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .llseek = generic_file_llseek,
Al Viro8e28bc72013-05-22 16:34:19 -0400395 .iterate = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 .read = generic_read_dir,
397};
398
James Hogan9e443bc2013-11-14 21:15:13 +0000399static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
401 struct address_space *mapping = page->mapping;
402 struct inode *inode = mapping->host;
403 char *buffer;
404 unsigned long long base;
405 int count = PAGE_CACHE_SIZE;
406 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
407 int err;
408
409 if (page->index >= end_index)
410 count = inode->i_size & (PAGE_CACHE_SIZE-1);
411
412 buffer = kmap(page);
413 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
414
415 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700416 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 ClearPageUptodate(page);
418 goto out;
419 }
420
421 if (base > inode->i_size)
422 inode->i_size = base;
423
424 if (PageError(page))
425 ClearPageError(page);
426 err = 0;
427
428 out:
429 kunmap(page);
430
431 unlock_page(page);
432 return err;
433}
434
James Hogan9e443bc2013-11-14 21:15:13 +0000435static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
437 char *buffer;
438 long long start;
439 int err = 0;
440
441 start = (long long) page->index << PAGE_CACHE_SHIFT;
442 buffer = kmap(page);
443 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
444 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700445 if (err < 0)
446 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
449
450 flush_dcache_page(page);
451 SetPageUptodate(page);
452 if (PageError(page)) ClearPageError(page);
453 err = 0;
454 out:
455 kunmap(page);
456 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700457 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
James Hogan9e443bc2013-11-14 21:15:13 +0000460static int hostfs_write_begin(struct file *file, struct address_space *mapping,
461 loff_t pos, unsigned len, unsigned flags,
462 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
Nick Pigginae361ff2007-10-16 01:25:17 -0700464 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Nick Piggin54566b22009-01-04 12:00:53 -0800466 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700467 if (!*pagep)
468 return -ENOMEM;
469 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470}
471
James Hogan9e443bc2013-11-14 21:15:13 +0000472static int hostfs_write_end(struct file *file, struct address_space *mapping,
473 loff_t pos, unsigned len, unsigned copied,
474 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700477 void *buffer;
478 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
479 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700482 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700484
485 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
486 SetPageUptodate(page);
487
Jeff Dike84b3db02007-10-16 01:27:13 -0700488 /*
489 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700490 * i_size against the last byte written.
491 */
492 if (err > 0 && (pos > inode->i_size))
493 inode->i_size = pos;
494 unlock_page(page);
495 page_cache_release(page);
496
Jeff Dikef1adc052007-05-08 00:23:18 -0700497 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700500static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 .writepage = hostfs_writepage,
502 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700503 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700504 .write_begin = hostfs_write_begin,
505 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506};
507
Al Viro4754b822010-06-06 20:33:12 -0400508static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
Al Viro4754b822010-06-06 20:33:12 -0400510 dev_t rdev;
511 struct hostfs_stat st;
512 int err = stat_file(name, &st, -1);
513 if (err)
514 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Al Viro5e2df282010-06-06 19:38:18 -0400516 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400517 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Al Viro4754b822010-06-06 20:33:12 -0400519 switch (st.mode & S_IFMT) {
520 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400521 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400522 break;
523 case S_IFDIR:
524 ino->i_op = &hostfs_dir_iops;
525 ino->i_fop = &hostfs_dir_fops;
526 break;
527 case S_IFCHR:
528 case S_IFBLK:
529 case S_IFIFO:
530 case S_IFSOCK:
531 init_special_inode(ino, st.mode & S_IFMT, rdev);
532 ino->i_op = &hostfs_iops;
533 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Al Viro4754b822010-06-06 20:33:12 -0400535 default:
536 ino->i_op = &hostfs_iops;
537 ino->i_fop = &hostfs_file_fops;
538 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
Al Viro4754b822010-06-06 20:33:12 -0400540
541 ino->i_ino = st.ino;
542 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200543 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800544 i_uid_write(ino, st.uid);
545 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400546 ino->i_atime = st.atime;
547 ino->i_mtime = st.mtime;
548 ino->i_ctime = st.ctime;
549 ino->i_size = st.size;
550 ino->i_blocks = st.blocks;
551 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552}
553
James Hogan9e443bc2013-11-14 21:15:13 +0000554static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
555 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{
557 struct inode *inode;
558 char *name;
559 int error, fd;
560
David Howells0a370e52008-02-07 00:15:50 -0800561 inode = hostfs_iget(dir->i_sb);
562 if (IS_ERR(inode)) {
563 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700564 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400568 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700569 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 goto out_put;
571
572 fd = file_create(name,
573 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
574 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
575 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400576 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400578 else
Al Viro5e2df282010-06-06 19:38:18 -0400579 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Al Viroe9193052010-06-06 23:16:34 -0400581 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700582 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 goto out_put;
584
585 HOSTFS_I(inode)->fd = fd;
586 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
587 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700588 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
590 out_put:
591 iput(inode);
592 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700593 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594}
595
James Hogan9e443bc2013-11-14 21:15:13 +0000596static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
597 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598{
599 struct inode *inode;
600 char *name;
601 int err;
602
David Howells0a370e52008-02-07 00:15:50 -0800603 inode = hostfs_iget(ino->i_sb);
604 if (IS_ERR(inode)) {
605 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400610 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700611 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto out_put;
613
614 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400615
Al Viroe9193052010-06-06 23:16:34 -0400616 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700617 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 iput(inode);
619 inode = NULL;
620 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700621 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 goto out_put;
623
624 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700625 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
627 out_put:
628 iput(inode);
629 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700630 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
James Hogan9e443bc2013-11-14 21:15:13 +0000633static int hostfs_link(struct dentry *to, struct inode *ino,
634 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635{
Jeff Dikef1adc052007-05-08 00:23:18 -0700636 char *from_name, *to_name;
637 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Al Viroc5322222010-06-06 20:42:10 -0400639 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700640 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400641 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700642 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400643 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700644 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700646 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400647 __putname(from_name);
648 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
651
James Hogan9e443bc2013-11-14 21:15:13 +0000652static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653{
654 char *file;
655 int err;
656
Jeff Dike84b3db02007-10-16 01:27:13 -0700657 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700658 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Al Virof8d7e182010-06-06 23:19:04 -0400660 if ((file = dentry_name(dentry)) == NULL)
661 return -ENOMEM;
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400664 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700665 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666}
667
James Hogan9e443bc2013-11-14 21:15:13 +0000668static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
669 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 char *file;
672 int err;
673
Al Viroc5322222010-06-06 20:42:10 -0400674 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700675 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 err = make_symlink(file, to);
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_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 char *file;
684 int err;
685
Al Viroc5322222010-06-06 20:42:10 -0400686 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700687 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400689 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691}
692
James Hogan9e443bc2013-11-14 21:15:13 +0000693static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
695 char *file;
696 int err;
697
Al Viroc5322222010-06-06 20:42:10 -0400698 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700699 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400701 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700702 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703}
704
Al Viro1a67aaf2011-07-26 01:52:52 -0400705static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
707 struct inode *inode;
708 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800709 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
David Howells0a370e52008-02-07 00:15:50 -0800711 inode = hostfs_iget(dir->i_sb);
712 if (IS_ERR(inode)) {
713 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400718 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700719 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 goto out_put;
721
722 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800723 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400724 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 goto out_free;
726
727 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400728 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400729 if (err)
730 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700731 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 goto out_put;
733
734 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700735 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
737 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400738 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 out_put:
740 iput(inode);
741 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700742 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743}
744
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200745static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
746 struct inode *new_dir, struct dentry *new_dentry,
747 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200749 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 int err;
751
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200752 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
753 return -EINVAL;
754
755 old_name = dentry_name(old_dentry);
756 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700757 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200758 new_name = dentry_name(new_dentry);
759 if (new_name == NULL) {
760 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700761 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200763 if (!flags)
764 err = rename_file(old_name, new_name);
765 else
766 err = rename2_file(old_name, new_name, flags);
767
768 __putname(old_name);
769 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700770 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771}
772
James Hogan9e443bc2013-11-14 21:15:13 +0000773static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
775 char *name;
776 int r = 0, w = 0, x = 0, err;
777
Al Viro10556cb2011-06-20 19:28:19 -0400778 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100779 return -ECHILD;
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if (desired & MAY_READ) r = 1;
782 if (desired & MAY_WRITE) w = 1;
783 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400784 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700785 if (name == NULL)
786 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700789 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 err = 0;
791 else
792 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400793 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700794 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400795 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return err;
797}
798
James Hogan9e443bc2013-11-14 21:15:13 +0000799static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800{
Christoph Hellwig10257742010-06-04 11:30:02 +0200801 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 struct hostfs_iattr attrs;
803 char *name;
804 int err;
805
Christoph Hellwig10257742010-06-04 11:30:02 +0200806 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700807
Christoph Hellwig10257742010-06-04 11:30:02 +0200808 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 if (err)
810 return err;
811
Jeff Dike84b3db02007-10-16 01:27:13 -0700812 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 attr->ia_valid &= ~ATTR_SIZE;
814
815 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700816 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 attrs.ia_valid |= HOSTFS_ATTR_MODE;
818 attrs.ia_mode = attr->ia_mode;
819 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700820 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800822 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700824 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800826 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700828 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
830 attrs.ia_size = attr->ia_size;
831 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700832 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
834 attrs.ia_atime = attr->ia_atime;
835 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700836 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
838 attrs.ia_mtime = attr->ia_mtime;
839 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700840 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
842 attrs.ia_ctime = attr->ia_ctime;
843 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700844 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
846 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700847 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
849 }
Al Viroc5322222010-06-06 20:42:10 -0400850 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700851 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700852 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700853 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400854 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700855 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700856 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Christoph Hellwig10257742010-06-04 11:30:02 +0200858 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200859 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200860 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200861
862 setattr_copy(inode, attr);
863 mark_inode_dirty(inode);
864 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865}
866
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800867static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 .permission = hostfs_permission,
869 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870};
871
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800872static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 .create = hostfs_create,
874 .lookup = hostfs_lookup,
875 .link = hostfs_link,
876 .unlink = hostfs_unlink,
877 .symlink = hostfs_symlink,
878 .mkdir = hostfs_mkdir,
879 .rmdir = hostfs_rmdir,
880 .mknod = hostfs_mknod,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200881 .rename2 = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 .permission = hostfs_permission,
883 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884};
885
Al Virod0352d32010-06-06 21:51:16 -0400886static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
Al Virod0352d32010-06-06 21:51:16 -0400888 char *link = __getname();
889 if (link) {
890 char *path = dentry_name(dentry);
891 int err = -ENOMEM;
892 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400893 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400894 if (err == PATH_MAX)
895 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400896 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400897 }
898 if (err < 0) {
899 __putname(link);
900 link = ERR_PTR(err);
901 }
902 } else {
903 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 }
Al Virod0352d32010-06-06 21:51:16 -0400905
906 nd_set_link(nd, link);
907 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908}
909
Al Virod0352d32010-06-06 21:51:16 -0400910static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
911{
912 char *s = nd_get_link(nd);
913 if (!IS_ERR(s))
914 __putname(s);
915}
916
917static const struct inode_operations hostfs_link_iops = {
918 .readlink = generic_readlink,
919 .follow_link = hostfs_follow_link,
920 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921};
922
923static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
924{
925 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700926 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 int err;
928
929 sb->s_blocksize = 1024;
930 sb->s_blocksize_bits = 10;
931 sb->s_magic = HOSTFS_SUPER_MAGIC;
932 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400933 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700934 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800936 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700937 if (req_root == NULL)
938 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400941 sb->s_fs_info = host_root_path =
942 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700943 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 goto out;
945
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700946 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Al Viro52b209f72010-06-06 18:43:19 -0400948 root_inode = new_inode(sb);
949 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400950 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Al Viro4754b822010-06-06 20:33:12 -0400952 err = read_name(root_inode, host_root_path);
953 if (err)
954 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400955
Al Viro4754b822010-06-06 20:33:12 -0400956 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400957 char *name = follow_link(host_root_path);
958 if (IS_ERR(name))
959 err = PTR_ERR(name);
960 else
961 err = read_name(root_inode, name);
962 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400963 if (err)
964 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500968 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700969 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500970 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Jeff Dikef1adc052007-05-08 00:23:18 -0700972 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Jeff Dikef1adc052007-05-08 00:23:18 -0700974out_put:
975 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700976out:
977 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978}
979
Al Viro3c26ff62010-07-25 11:46:36 +0400980static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700981 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400982 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983{
Al Viro3c26ff62010-07-25 11:46:36 +0400984 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985}
986
Al Viro601d2c32010-06-06 17:53:01 -0400987static void hostfs_kill_sb(struct super_block *s)
988{
989 kill_anon_super(s);
990 kfree(s->s_fs_info);
991}
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993static struct file_system_type hostfs_type = {
994 .owner = THIS_MODULE,
995 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400996 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400997 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 .fs_flags = 0,
999};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -07001000MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002static int __init init_hostfs(void)
1003{
Jeff Dikef1adc052007-05-08 00:23:18 -07001004 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005}
1006
1007static void __exit exit_hostfs(void)
1008{
1009 unregister_filesystem(&hostfs_type);
1010}
1011
1012module_init(init_hostfs)
1013module_exit(exit_hostfs)
1014MODULE_LICENSE("GPL");