blob: 112ba5aa0848d510ad75ac73986ceb5a9312a824 [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);
Richard Weinbergeraf955652015-02-27 22:56:28 +0100332 close_file(&fd);
Al Virof8ad8502010-06-06 23:49:18 -0400333 return 0;
334 }
335 if ((mode | HOSTFS_I(ino)->mode) != mode) {
336 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100337 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400338 close_file(&fd);
339 goto retry;
340 }
341 if (HOSTFS_I(ino)->fd == -1) {
342 HOSTFS_I(ino)->fd = fd;
343 } else {
344 err = replace_file(fd, HOSTFS_I(ino)->fd);
345 close_file(&fd);
346 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100347 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400348 return err;
349 }
350 }
351 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100352 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Jeff Dikef1adc052007-05-08 00:23:18 -0700354 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
Richard Weinberger65984ff2013-08-04 17:23:51 +0000357static int hostfs_file_release(struct inode *inode, struct file *file)
358{
359 filemap_write_and_wait(inode->i_mapping);
360
361 return 0;
362}
363
James Hogan9e443bc2013-11-14 21:15:13 +0000364static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
365 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Josef Bacik02c24a82011-07-16 20:44:56 -0400367 struct inode *inode = file->f_mapping->host;
368 int ret;
369
370 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
371 if (ret)
372 return ret;
373
374 mutex_lock(&inode->i_mutex);
375 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
376 mutex_unlock(&inode->i_mutex);
377
378 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379}
380
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800381static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 .llseek = generic_file_llseek,
Al Viroaad4f8b2014-04-02 14:33:16 -0400383 .read = new_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200384 .splice_read = generic_file_splice_read,
Al Viroaad4f8b2014-04-02 14:33:16 -0400385 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400386 .write_iter = generic_file_write_iter,
387 .write = new_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 .mmap = generic_file_mmap,
389 .open = hostfs_file_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000390 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 .fsync = hostfs_fsync,
392};
393
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800394static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 .llseek = generic_file_llseek,
Al Viro8e28bc72013-05-22 16:34:19 -0400396 .iterate = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 .read = generic_read_dir,
398};
399
James Hogan9e443bc2013-11-14 21:15:13 +0000400static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401{
402 struct address_space *mapping = page->mapping;
403 struct inode *inode = mapping->host;
404 char *buffer;
405 unsigned long long base;
406 int count = PAGE_CACHE_SIZE;
407 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
408 int err;
409
410 if (page->index >= end_index)
411 count = inode->i_size & (PAGE_CACHE_SIZE-1);
412
413 buffer = kmap(page);
414 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
415
416 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700417 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 ClearPageUptodate(page);
419 goto out;
420 }
421
422 if (base > inode->i_size)
423 inode->i_size = base;
424
425 if (PageError(page))
426 ClearPageError(page);
427 err = 0;
428
429 out:
430 kunmap(page);
431
432 unlock_page(page);
433 return err;
434}
435
James Hogan9e443bc2013-11-14 21:15:13 +0000436static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 char *buffer;
439 long long start;
440 int err = 0;
441
442 start = (long long) page->index << PAGE_CACHE_SHIFT;
443 buffer = kmap(page);
444 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
445 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700446 if (err < 0)
447 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
450
451 flush_dcache_page(page);
452 SetPageUptodate(page);
453 if (PageError(page)) ClearPageError(page);
454 err = 0;
455 out:
456 kunmap(page);
457 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700458 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459}
460
James Hogan9e443bc2013-11-14 21:15:13 +0000461static int hostfs_write_begin(struct file *file, struct address_space *mapping,
462 loff_t pos, unsigned len, unsigned flags,
463 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464{
Nick Pigginae361ff2007-10-16 01:25:17 -0700465 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Nick Piggin54566b22009-01-04 12:00:53 -0800467 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700468 if (!*pagep)
469 return -ENOMEM;
470 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471}
472
James Hogan9e443bc2013-11-14 21:15:13 +0000473static int hostfs_write_end(struct file *file, struct address_space *mapping,
474 loff_t pos, unsigned len, unsigned copied,
475 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700478 void *buffer;
479 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
480 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700483 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700485
486 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
487 SetPageUptodate(page);
488
Jeff Dike84b3db02007-10-16 01:27:13 -0700489 /*
490 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700491 * i_size against the last byte written.
492 */
493 if (err > 0 && (pos > inode->i_size))
494 inode->i_size = pos;
495 unlock_page(page);
496 page_cache_release(page);
497
Jeff Dikef1adc052007-05-08 00:23:18 -0700498 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499}
500
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700501static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 .writepage = hostfs_writepage,
503 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700504 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700505 .write_begin = hostfs_write_begin,
506 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507};
508
Al Viro4754b822010-06-06 20:33:12 -0400509static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
Al Viro4754b822010-06-06 20:33:12 -0400511 dev_t rdev;
512 struct hostfs_stat st;
513 int err = stat_file(name, &st, -1);
514 if (err)
515 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Al Viro5e2df282010-06-06 19:38:18 -0400517 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400518 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Al Viro4754b822010-06-06 20:33:12 -0400520 switch (st.mode & S_IFMT) {
521 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400522 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400523 break;
524 case S_IFDIR:
525 ino->i_op = &hostfs_dir_iops;
526 ino->i_fop = &hostfs_dir_fops;
527 break;
528 case S_IFCHR:
529 case S_IFBLK:
530 case S_IFIFO:
531 case S_IFSOCK:
532 init_special_inode(ino, st.mode & S_IFMT, rdev);
533 ino->i_op = &hostfs_iops;
534 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Al Viro4754b822010-06-06 20:33:12 -0400536 default:
537 ino->i_op = &hostfs_iops;
538 ino->i_fop = &hostfs_file_fops;
539 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }
Al Viro4754b822010-06-06 20:33:12 -0400541
542 ino->i_ino = st.ino;
543 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200544 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800545 i_uid_write(ino, st.uid);
546 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400547 ino->i_atime = st.atime;
548 ino->i_mtime = st.mtime;
549 ino->i_ctime = st.ctime;
550 ino->i_size = st.size;
551 ino->i_blocks = st.blocks;
552 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553}
554
James Hogan9e443bc2013-11-14 21:15:13 +0000555static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
556 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557{
558 struct inode *inode;
559 char *name;
560 int error, fd;
561
David Howells0a370e52008-02-07 00:15:50 -0800562 inode = hostfs_iget(dir->i_sb);
563 if (IS_ERR(inode)) {
564 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700565 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400569 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700570 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 goto out_put;
572
573 fd = file_create(name,
574 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
575 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
576 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400577 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400579 else
Al Viro5e2df282010-06-06 19:38:18 -0400580 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Al Viroe9193052010-06-06 23:16:34 -0400582 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700583 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 goto out_put;
585
586 HOSTFS_I(inode)->fd = fd;
587 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
588 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700589 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
591 out_put:
592 iput(inode);
593 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700594 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595}
596
James Hogan9e443bc2013-11-14 21:15:13 +0000597static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
598 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
600 struct inode *inode;
601 char *name;
602 int err;
603
David Howells0a370e52008-02-07 00:15:50 -0800604 inode = hostfs_iget(ino->i_sb);
605 if (IS_ERR(inode)) {
606 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400611 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700612 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 goto out_put;
614
615 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400616
Al Viroe9193052010-06-06 23:16:34 -0400617 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700618 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 iput(inode);
620 inode = NULL;
621 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700622 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 goto out_put;
624
625 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700626 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628 out_put:
629 iput(inode);
630 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700631 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632}
633
James Hogan9e443bc2013-11-14 21:15:13 +0000634static int hostfs_link(struct dentry *to, struct inode *ino,
635 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
Jeff Dikef1adc052007-05-08 00:23:18 -0700637 char *from_name, *to_name;
638 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
Al Viroc5322222010-06-06 20:42:10 -0400640 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700641 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400642 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700643 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400644 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700645 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700647 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400648 __putname(from_name);
649 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700650 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651}
652
James Hogan9e443bc2013-11-14 21:15:13 +0000653static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654{
655 char *file;
656 int err;
657
Jeff Dike84b3db02007-10-16 01:27:13 -0700658 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700659 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Al Virof8d7e182010-06-06 23:19:04 -0400661 if ((file = dentry_name(dentry)) == NULL)
662 return -ENOMEM;
663
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400665 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700666 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667}
668
James Hogan9e443bc2013-11-14 21:15:13 +0000669static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
670 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671{
672 char *file;
673 int err;
674
Al Viroc5322222010-06-06 20:42:10 -0400675 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 err = make_symlink(file, to);
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_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
684 char *file;
685 int err;
686
Al Viroc5322222010-06-06 20:42:10 -0400687 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400690 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700691 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692}
693
James Hogan9e443bc2013-11-14 21:15:13 +0000694static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
696 char *file;
697 int err;
698
Al Viroc5322222010-06-06 20:42:10 -0400699 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700700 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400702 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700703 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704}
705
Al Viro1a67aaf2011-07-26 01:52:52 -0400706static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
708 struct inode *inode;
709 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800710 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
David Howells0a370e52008-02-07 00:15:50 -0800712 inode = hostfs_iget(dir->i_sb);
713 if (IS_ERR(inode)) {
714 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800716 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400719 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700720 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 goto out_put;
722
723 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800724 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400725 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 goto out_free;
727
728 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400729 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400730 if (err)
731 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700732 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 goto out_put;
734
735 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700736 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400739 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 out_put:
741 iput(inode);
742 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700743 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744}
745
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200746static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
747 struct inode *new_dir, struct dentry *new_dentry,
748 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200750 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 int err;
752
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200753 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
754 return -EINVAL;
755
756 old_name = dentry_name(old_dentry);
757 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700758 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200759 new_name = dentry_name(new_dentry);
760 if (new_name == NULL) {
761 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700762 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200764 if (!flags)
765 err = rename_file(old_name, new_name);
766 else
767 err = rename2_file(old_name, new_name, flags);
768
769 __putname(old_name);
770 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700771 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772}
773
James Hogan9e443bc2013-11-14 21:15:13 +0000774static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 char *name;
777 int r = 0, w = 0, x = 0, err;
778
Al Viro10556cb2011-06-20 19:28:19 -0400779 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100780 return -ECHILD;
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (desired & MAY_READ) r = 1;
783 if (desired & MAY_WRITE) w = 1;
784 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400785 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700786 if (name == NULL)
787 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700790 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 err = 0;
792 else
793 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400794 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700795 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400796 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 return err;
798}
799
James Hogan9e443bc2013-11-14 21:15:13 +0000800static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
Christoph Hellwig10257742010-06-04 11:30:02 +0200802 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 struct hostfs_iattr attrs;
804 char *name;
805 int err;
806
Christoph Hellwig10257742010-06-04 11:30:02 +0200807 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700808
Christoph Hellwig10257742010-06-04 11:30:02 +0200809 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 if (err)
811 return err;
812
Jeff Dike84b3db02007-10-16 01:27:13 -0700813 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 attr->ia_valid &= ~ATTR_SIZE;
815
816 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700817 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 attrs.ia_valid |= HOSTFS_ATTR_MODE;
819 attrs.ia_mode = attr->ia_mode;
820 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700821 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800823 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700825 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800827 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700829 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
831 attrs.ia_size = attr->ia_size;
832 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700833 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
835 attrs.ia_atime = attr->ia_atime;
836 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700837 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
839 attrs.ia_mtime = attr->ia_mtime;
840 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700841 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
843 attrs.ia_ctime = attr->ia_ctime;
844 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700845 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
847 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700848 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
850 }
Al Viroc5322222010-06-06 20:42:10 -0400851 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700852 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700853 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700854 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400855 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700856 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700857 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
Christoph Hellwig10257742010-06-04 11:30:02 +0200859 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200860 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200861 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200862
863 setattr_copy(inode, attr);
864 mark_inode_dirty(inode);
865 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866}
867
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800868static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 .permission = hostfs_permission,
870 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871};
872
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800873static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 .create = hostfs_create,
875 .lookup = hostfs_lookup,
876 .link = hostfs_link,
877 .unlink = hostfs_unlink,
878 .symlink = hostfs_symlink,
879 .mkdir = hostfs_mkdir,
880 .rmdir = hostfs_rmdir,
881 .mknod = hostfs_mknod,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200882 .rename2 = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 .permission = hostfs_permission,
884 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885};
886
Al Virod0352d32010-06-06 21:51:16 -0400887static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Al Virod0352d32010-06-06 21:51:16 -0400889 char *link = __getname();
890 if (link) {
891 char *path = dentry_name(dentry);
892 int err = -ENOMEM;
893 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400894 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400895 if (err == PATH_MAX)
896 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400897 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400898 }
899 if (err < 0) {
900 __putname(link);
901 link = ERR_PTR(err);
902 }
903 } else {
904 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
Al Virod0352d32010-06-06 21:51:16 -0400906
907 nd_set_link(nd, link);
908 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909}
910
Al Virod0352d32010-06-06 21:51:16 -0400911static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
912{
913 char *s = nd_get_link(nd);
914 if (!IS_ERR(s))
915 __putname(s);
916}
917
918static const struct inode_operations hostfs_link_iops = {
919 .readlink = generic_readlink,
920 .follow_link = hostfs_follow_link,
921 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922};
923
924static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
925{
926 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700927 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 int err;
929
930 sb->s_blocksize = 1024;
931 sb->s_blocksize_bits = 10;
932 sb->s_magic = HOSTFS_SUPER_MAGIC;
933 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400934 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700935 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800937 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700938 if (req_root == NULL)
939 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400942 sb->s_fs_info = host_root_path =
943 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700944 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 goto out;
946
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700947 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Al Viro52b209f72010-06-06 18:43:19 -0400949 root_inode = new_inode(sb);
950 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400951 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Al Viro4754b822010-06-06 20:33:12 -0400953 err = read_name(root_inode, host_root_path);
954 if (err)
955 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400956
Al Viro4754b822010-06-06 20:33:12 -0400957 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400958 char *name = follow_link(host_root_path);
959 if (IS_ERR(name))
960 err = PTR_ERR(name);
961 else
962 err = read_name(root_inode, name);
963 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400964 if (err)
965 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500969 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700970 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500971 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Jeff Dikef1adc052007-05-08 00:23:18 -0700973 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Jeff Dikef1adc052007-05-08 00:23:18 -0700975out_put:
976 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700977out:
978 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979}
980
Al Viro3c26ff62010-07-25 11:46:36 +0400981static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700982 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400983 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984{
Al Viro3c26ff62010-07-25 11:46:36 +0400985 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986}
987
Al Viro601d2c32010-06-06 17:53:01 -0400988static void hostfs_kill_sb(struct super_block *s)
989{
990 kill_anon_super(s);
991 kfree(s->s_fs_info);
992}
993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994static struct file_system_type hostfs_type = {
995 .owner = THIS_MODULE,
996 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400997 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400998 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 .fs_flags = 0,
1000};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -07001001MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003static int __init init_hostfs(void)
1004{
Jeff Dikef1adc052007-05-08 00:23:18 -07001005 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006}
1007
1008static void __exit exit_hostfs(void)
1009{
1010 unregister_filesystem(&hostfs_type);
1011}
1012
1013module_init(init_hostfs)
1014module_exit(exit_hostfs)
1015MODULE_LICENSE("GPL");