blob: 92b008f564a457127f83c6db084d84f82fb0c9c8 [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
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100298static int hostfs_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,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100389 .open = hostfs_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,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100398 .open = hostfs_open,
399 .fsync = hostfs_fsync,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400};
401
James Hogan9e443bc2013-11-14 21:15:13 +0000402static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
404 struct address_space *mapping = page->mapping;
405 struct inode *inode = mapping->host;
406 char *buffer;
407 unsigned long long base;
408 int count = PAGE_CACHE_SIZE;
409 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
410 int err;
411
412 if (page->index >= end_index)
413 count = inode->i_size & (PAGE_CACHE_SIZE-1);
414
415 buffer = kmap(page);
416 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
417
418 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700419 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 ClearPageUptodate(page);
421 goto out;
422 }
423
424 if (base > inode->i_size)
425 inode->i_size = base;
426
427 if (PageError(page))
428 ClearPageError(page);
429 err = 0;
430
431 out:
432 kunmap(page);
433
434 unlock_page(page);
435 return err;
436}
437
James Hogan9e443bc2013-11-14 21:15:13 +0000438static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 char *buffer;
441 long long start;
442 int err = 0;
443
444 start = (long long) page->index << PAGE_CACHE_SHIFT;
445 buffer = kmap(page);
446 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
447 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700448 if (err < 0)
449 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
452
453 flush_dcache_page(page);
454 SetPageUptodate(page);
455 if (PageError(page)) ClearPageError(page);
456 err = 0;
457 out:
458 kunmap(page);
459 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700460 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461}
462
James Hogan9e443bc2013-11-14 21:15:13 +0000463static int hostfs_write_begin(struct file *file, struct address_space *mapping,
464 loff_t pos, unsigned len, unsigned flags,
465 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Nick Pigginae361ff2007-10-16 01:25:17 -0700467 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Nick Piggin54566b22009-01-04 12:00:53 -0800469 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700470 if (!*pagep)
471 return -ENOMEM;
472 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473}
474
James Hogan9e443bc2013-11-14 21:15:13 +0000475static int hostfs_write_end(struct file *file, struct address_space *mapping,
476 loff_t pos, unsigned len, unsigned copied,
477 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700480 void *buffer;
481 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
482 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700485 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700487
488 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
489 SetPageUptodate(page);
490
Jeff Dike84b3db02007-10-16 01:27:13 -0700491 /*
492 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700493 * i_size against the last byte written.
494 */
495 if (err > 0 && (pos > inode->i_size))
496 inode->i_size = pos;
497 unlock_page(page);
498 page_cache_release(page);
499
Jeff Dikef1adc052007-05-08 00:23:18 -0700500 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501}
502
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700503static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 .writepage = hostfs_writepage,
505 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700506 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700507 .write_begin = hostfs_write_begin,
508 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509};
510
Al Viro4754b822010-06-06 20:33:12 -0400511static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
Al Viro4754b822010-06-06 20:33:12 -0400513 dev_t rdev;
514 struct hostfs_stat st;
515 int err = stat_file(name, &st, -1);
516 if (err)
517 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Al Viro5e2df282010-06-06 19:38:18 -0400519 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400520 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Al Viro4754b822010-06-06 20:33:12 -0400522 switch (st.mode & S_IFMT) {
523 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400524 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400525 break;
526 case S_IFDIR:
527 ino->i_op = &hostfs_dir_iops;
528 ino->i_fop = &hostfs_dir_fops;
529 break;
530 case S_IFCHR:
531 case S_IFBLK:
532 case S_IFIFO:
533 case S_IFSOCK:
534 init_special_inode(ino, st.mode & S_IFMT, rdev);
535 ino->i_op = &hostfs_iops;
536 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Al Viro4754b822010-06-06 20:33:12 -0400538 default:
539 ino->i_op = &hostfs_iops;
540 ino->i_fop = &hostfs_file_fops;
541 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 }
Al Viro4754b822010-06-06 20:33:12 -0400543
544 ino->i_ino = st.ino;
545 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200546 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800547 i_uid_write(ino, st.uid);
548 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400549 ino->i_atime = st.atime;
550 ino->i_mtime = st.mtime;
551 ino->i_ctime = st.ctime;
552 ino->i_size = st.size;
553 ino->i_blocks = st.blocks;
554 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555}
556
James Hogan9e443bc2013-11-14 21:15:13 +0000557static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
558 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559{
560 struct inode *inode;
561 char *name;
562 int error, fd;
563
David Howells0a370e52008-02-07 00:15:50 -0800564 inode = hostfs_iget(dir->i_sb);
565 if (IS_ERR(inode)) {
566 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700567 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400571 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700572 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 goto out_put;
574
575 fd = file_create(name,
576 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
577 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
578 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400579 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400581 else
Al Viro5e2df282010-06-06 19:38:18 -0400582 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Al Viroe9193052010-06-06 23:16:34 -0400584 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700585 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 goto out_put;
587
588 HOSTFS_I(inode)->fd = fd;
589 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
590 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700591 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
593 out_put:
594 iput(inode);
595 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700596 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597}
598
James Hogan9e443bc2013-11-14 21:15:13 +0000599static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
600 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 struct inode *inode;
603 char *name;
604 int err;
605
David Howells0a370e52008-02-07 00:15:50 -0800606 inode = hostfs_iget(ino->i_sb);
607 if (IS_ERR(inode)) {
608 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400613 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700614 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 goto out_put;
616
617 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400618
Al Viroe9193052010-06-06 23:16:34 -0400619 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700620 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 iput(inode);
622 inode = NULL;
623 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700624 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 goto out_put;
626
627 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700628 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 out_put:
631 iput(inode);
632 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700633 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
635
James Hogan9e443bc2013-11-14 21:15:13 +0000636static int hostfs_link(struct dentry *to, struct inode *ino,
637 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 char *from_name, *to_name;
640 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Al Viroc5322222010-06-06 20:42:10 -0400642 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700643 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400644 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700645 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400646 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700647 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400650 __putname(from_name);
651 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700652 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653}
654
James Hogan9e443bc2013-11-14 21:15:13 +0000655static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
657 char *file;
658 int err;
659
Jeff Dike84b3db02007-10-16 01:27:13 -0700660 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700661 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Al Virof8d7e182010-06-06 23:19:04 -0400663 if ((file = dentry_name(dentry)) == NULL)
664 return -ENOMEM;
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400667 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700668 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669}
670
James Hogan9e443bc2013-11-14 21:15:13 +0000671static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
672 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 char *file;
675 int err;
676
Al Viroc5322222010-06-06 20:42:10 -0400677 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700678 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400680 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700681 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682}
683
James Hogan9e443bc2013-11-14 21:15:13 +0000684static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
686 char *file;
687 int err;
688
Al Viroc5322222010-06-06 20:42:10 -0400689 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400692 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700693 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694}
695
James Hogan9e443bc2013-11-14 21:15:13 +0000696static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697{
698 char *file;
699 int err;
700
Al Viroc5322222010-06-06 20:42:10 -0400701 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700702 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400704 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700705 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706}
707
Al Viro1a67aaf2011-07-26 01:52:52 -0400708static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709{
710 struct inode *inode;
711 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800712 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
David Howells0a370e52008-02-07 00:15:50 -0800714 inode = hostfs_iget(dir->i_sb);
715 if (IS_ERR(inode)) {
716 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400721 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700722 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 goto out_put;
724
725 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800726 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400727 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 goto out_free;
729
730 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400731 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400732 if (err)
733 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700734 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 goto out_put;
736
737 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700738 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
740 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400741 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 out_put:
743 iput(inode);
744 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700745 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746}
747
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200748static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
749 struct inode *new_dir, struct dentry *new_dentry,
750 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200752 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 int err;
754
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200755 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
756 return -EINVAL;
757
758 old_name = dentry_name(old_dentry);
759 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700760 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200761 new_name = dentry_name(new_dentry);
762 if (new_name == NULL) {
763 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700764 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200766 if (!flags)
767 err = rename_file(old_name, new_name);
768 else
769 err = rename2_file(old_name, new_name, flags);
770
771 __putname(old_name);
772 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700773 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774}
775
James Hogan9e443bc2013-11-14 21:15:13 +0000776static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
778 char *name;
779 int r = 0, w = 0, x = 0, err;
780
Al Viro10556cb2011-06-20 19:28:19 -0400781 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100782 return -ECHILD;
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (desired & MAY_READ) r = 1;
785 if (desired & MAY_WRITE) w = 1;
786 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400787 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700788 if (name == NULL)
789 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700792 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 err = 0;
794 else
795 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400796 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700797 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400798 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 return err;
800}
801
James Hogan9e443bc2013-11-14 21:15:13 +0000802static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
Christoph Hellwig10257742010-06-04 11:30:02 +0200804 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 struct hostfs_iattr attrs;
806 char *name;
807 int err;
808
Christoph Hellwig10257742010-06-04 11:30:02 +0200809 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700810
Christoph Hellwig10257742010-06-04 11:30:02 +0200811 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 if (err)
813 return err;
814
Jeff Dike84b3db02007-10-16 01:27:13 -0700815 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 attr->ia_valid &= ~ATTR_SIZE;
817
818 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700819 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 attrs.ia_valid |= HOSTFS_ATTR_MODE;
821 attrs.ia_mode = attr->ia_mode;
822 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700823 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800825 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700827 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800829 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700831 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
833 attrs.ia_size = attr->ia_size;
834 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700835 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
837 attrs.ia_atime = attr->ia_atime;
838 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
841 attrs.ia_mtime = attr->ia_mtime;
842 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700843 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
845 attrs.ia_ctime = attr->ia_ctime;
846 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700847 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
849 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700850 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
852 }
Al Viroc5322222010-06-06 20:42:10 -0400853 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700854 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700855 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700856 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400857 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700858 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700859 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Christoph Hellwig10257742010-06-04 11:30:02 +0200861 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200862 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200863 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200864
865 setattr_copy(inode, attr);
866 mark_inode_dirty(inode);
867 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868}
869
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800870static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 .permission = hostfs_permission,
872 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873};
874
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800875static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 .create = hostfs_create,
877 .lookup = hostfs_lookup,
878 .link = hostfs_link,
879 .unlink = hostfs_unlink,
880 .symlink = hostfs_symlink,
881 .mkdir = hostfs_mkdir,
882 .rmdir = hostfs_rmdir,
883 .mknod = hostfs_mknod,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200884 .rename2 = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 .permission = hostfs_permission,
886 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887};
888
Al Virod0352d32010-06-06 21:51:16 -0400889static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
Al Virod0352d32010-06-06 21:51:16 -0400891 char *link = __getname();
892 if (link) {
893 char *path = dentry_name(dentry);
894 int err = -ENOMEM;
895 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400896 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400897 if (err == PATH_MAX)
898 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400899 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400900 }
901 if (err < 0) {
902 __putname(link);
903 link = ERR_PTR(err);
904 }
905 } else {
906 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
Al Virod0352d32010-06-06 21:51:16 -0400908
909 nd_set_link(nd, link);
910 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911}
912
Al Virod0352d32010-06-06 21:51:16 -0400913static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
914{
915 char *s = nd_get_link(nd);
916 if (!IS_ERR(s))
917 __putname(s);
918}
919
920static const struct inode_operations hostfs_link_iops = {
921 .readlink = generic_readlink,
922 .follow_link = hostfs_follow_link,
923 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924};
925
926static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
927{
928 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700929 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 int err;
931
932 sb->s_blocksize = 1024;
933 sb->s_blocksize_bits = 10;
934 sb->s_magic = HOSTFS_SUPER_MAGIC;
935 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400936 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700937 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800939 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700940 if (req_root == NULL)
941 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400944 sb->s_fs_info = host_root_path =
945 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700946 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 goto out;
948
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700949 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Al Viro52b209f72010-06-06 18:43:19 -0400951 root_inode = new_inode(sb);
952 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400953 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Al Viro4754b822010-06-06 20:33:12 -0400955 err = read_name(root_inode, host_root_path);
956 if (err)
957 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400958
Al Viro4754b822010-06-06 20:33:12 -0400959 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400960 char *name = follow_link(host_root_path);
961 if (IS_ERR(name))
962 err = PTR_ERR(name);
963 else
964 err = read_name(root_inode, name);
965 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400966 if (err)
967 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500971 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700972 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500973 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Jeff Dikef1adc052007-05-08 00:23:18 -0700975 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Jeff Dikef1adc052007-05-08 00:23:18 -0700977out_put:
978 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700979out:
980 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981}
982
Al Viro3c26ff62010-07-25 11:46:36 +0400983static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700984 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400985 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
Al Viro3c26ff62010-07-25 11:46:36 +0400987 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988}
989
Al Viro601d2c32010-06-06 17:53:01 -0400990static void hostfs_kill_sb(struct super_block *s)
991{
992 kill_anon_super(s);
993 kfree(s->s_fs_info);
994}
995
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996static struct file_system_type hostfs_type = {
997 .owner = THIS_MODULE,
998 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400999 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -04001000 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 .fs_flags = 0,
1002};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -07001003MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005static int __init init_hostfs(void)
1006{
Jeff Dikef1adc052007-05-08 00:23:18 -07001007 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008}
1009
1010static void __exit exit_hostfs(void)
1011{
1012 unregister_filesystem(&hostfs_type);
1013}
1014
1015module_init(init_hostfs)
1016module_exit(exit_hostfs)
1017MODULE_LICENSE("GPL");