blob: 8163aac81c21febcaec40a2968991c19fc7887ce [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;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100537 case S_IFREG:
Al Viro4754b822010-06-06 20:33:12 -0400538 ino->i_op = &hostfs_iops;
539 ino->i_fop = &hostfs_file_fops;
540 ino->i_mapping->a_ops = &hostfs_aops;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100541 break;
542 default:
543 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 }
Al Viro4754b822010-06-06 20:33:12 -0400545
546 ino->i_ino = st.ino;
547 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200548 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800549 i_uid_write(ino, st.uid);
550 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400551 ino->i_atime = st.atime;
552 ino->i_mtime = st.mtime;
553 ino->i_ctime = st.ctime;
554 ino->i_size = st.size;
555 ino->i_blocks = st.blocks;
556 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557}
558
James Hogan9e443bc2013-11-14 21:15:13 +0000559static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
560 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
562 struct inode *inode;
563 char *name;
564 int error, fd;
565
David Howells0a370e52008-02-07 00:15:50 -0800566 inode = hostfs_iget(dir->i_sb);
567 if (IS_ERR(inode)) {
568 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700569 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400573 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700574 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 goto out_put;
576
577 fd = file_create(name,
578 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
579 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
580 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400581 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400583 else
Al Viro5e2df282010-06-06 19:38:18 -0400584 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Al Viroe9193052010-06-06 23:16:34 -0400586 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700587 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 goto out_put;
589
590 HOSTFS_I(inode)->fd = fd;
591 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
592 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700593 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
595 out_put:
596 iput(inode);
597 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700598 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599}
600
James Hogan9e443bc2013-11-14 21:15:13 +0000601static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
602 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
604 struct inode *inode;
605 char *name;
606 int err;
607
David Howells0a370e52008-02-07 00:15:50 -0800608 inode = hostfs_iget(ino->i_sb);
609 if (IS_ERR(inode)) {
610 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400615 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700616 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 goto out_put;
618
619 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400620
Al Viroe9193052010-06-06 23:16:34 -0400621 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700622 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 iput(inode);
624 inode = NULL;
625 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700626 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 goto out_put;
628
629 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700630 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632 out_put:
633 iput(inode);
634 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700635 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636}
637
James Hogan9e443bc2013-11-14 21:15:13 +0000638static int hostfs_link(struct dentry *to, struct inode *ino,
639 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
Jeff Dikef1adc052007-05-08 00:23:18 -0700641 char *from_name, *to_name;
642 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Al Viroc5322222010-06-06 20:42:10 -0400644 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700645 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400646 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700647 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400648 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700651 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400652 __putname(from_name);
653 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700654 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
656
James Hogan9e443bc2013-11-14 21:15:13 +0000657static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658{
659 char *file;
660 int err;
661
Jeff Dike84b3db02007-10-16 01:27:13 -0700662 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700663 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
Al Virof8d7e182010-06-06 23:19:04 -0400665 if ((file = dentry_name(dentry)) == NULL)
666 return -ENOMEM;
667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400669 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700670 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671}
672
James Hogan9e443bc2013-11-14 21:15:13 +0000673static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
674 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 char *file;
677 int err;
678
Al Viroc5322222010-06-06 20:42:10 -0400679 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700680 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400682 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700683 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684}
685
James Hogan9e443bc2013-11-14 21:15:13 +0000686static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
688 char *file;
689 int err;
690
Al Viroc5322222010-06-06 20:42:10 -0400691 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700692 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400694 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700695 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696}
697
James Hogan9e443bc2013-11-14 21:15:13 +0000698static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699{
700 char *file;
701 int err;
702
Al Viroc5322222010-06-06 20:42:10 -0400703 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700704 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400706 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700707 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708}
709
Al Viro1a67aaf2011-07-26 01:52:52 -0400710static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
712 struct inode *inode;
713 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800714 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
David Howells0a370e52008-02-07 00:15:50 -0800716 inode = hostfs_iget(dir->i_sb);
717 if (IS_ERR(inode)) {
718 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800720 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400723 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700724 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 goto out_put;
726
727 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800728 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400729 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 goto out_free;
731
732 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400733 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400734 if (err)
735 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700736 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 goto out_put;
738
739 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700740 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400743 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 out_put:
745 iput(inode);
746 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700747 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200750static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
751 struct inode *new_dir, struct dentry *new_dentry,
752 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200754 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 int err;
756
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200757 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
758 return -EINVAL;
759
760 old_name = dentry_name(old_dentry);
761 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700762 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200763 new_name = dentry_name(new_dentry);
764 if (new_name == NULL) {
765 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700766 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200768 if (!flags)
769 err = rename_file(old_name, new_name);
770 else
771 err = rename2_file(old_name, new_name, flags);
772
773 __putname(old_name);
774 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700775 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776}
777
James Hogan9e443bc2013-11-14 21:15:13 +0000778static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
780 char *name;
781 int r = 0, w = 0, x = 0, err;
782
Al Viro10556cb2011-06-20 19:28:19 -0400783 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100784 return -ECHILD;
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (desired & MAY_READ) r = 1;
787 if (desired & MAY_WRITE) w = 1;
788 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400789 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700790 if (name == NULL)
791 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700794 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 err = 0;
796 else
797 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400798 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700799 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400800 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 return err;
802}
803
James Hogan9e443bc2013-11-14 21:15:13 +0000804static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
Christoph Hellwig10257742010-06-04 11:30:02 +0200806 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 struct hostfs_iattr attrs;
808 char *name;
809 int err;
810
Christoph Hellwig10257742010-06-04 11:30:02 +0200811 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700812
Christoph Hellwig10257742010-06-04 11:30:02 +0200813 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (err)
815 return err;
816
Jeff Dike84b3db02007-10-16 01:27:13 -0700817 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 attr->ia_valid &= ~ATTR_SIZE;
819
820 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700821 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 attrs.ia_valid |= HOSTFS_ATTR_MODE;
823 attrs.ia_mode = attr->ia_mode;
824 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700825 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800827 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700829 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800831 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700833 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
835 attrs.ia_size = attr->ia_size;
836 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700837 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
839 attrs.ia_atime = attr->ia_atime;
840 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700841 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
843 attrs.ia_mtime = attr->ia_mtime;
844 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700845 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
847 attrs.ia_ctime = attr->ia_ctime;
848 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700849 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
851 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700852 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
854 }
Al Viroc5322222010-06-06 20:42:10 -0400855 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700856 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700857 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700858 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400859 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700860 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700861 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Christoph Hellwig10257742010-06-04 11:30:02 +0200863 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200864 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200865 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200866
867 setattr_copy(inode, attr);
868 mark_inode_dirty(inode);
869 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870}
871
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800872static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 .permission = hostfs_permission,
874 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875};
876
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800877static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 .create = hostfs_create,
879 .lookup = hostfs_lookup,
880 .link = hostfs_link,
881 .unlink = hostfs_unlink,
882 .symlink = hostfs_symlink,
883 .mkdir = hostfs_mkdir,
884 .rmdir = hostfs_rmdir,
885 .mknod = hostfs_mknod,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200886 .rename2 = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 .permission = hostfs_permission,
888 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889};
890
Al Virod0352d32010-06-06 21:51:16 -0400891static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892{
Al Virod0352d32010-06-06 21:51:16 -0400893 char *link = __getname();
894 if (link) {
895 char *path = dentry_name(dentry);
896 int err = -ENOMEM;
897 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400898 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400899 if (err == PATH_MAX)
900 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400901 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400902 }
903 if (err < 0) {
904 __putname(link);
905 link = ERR_PTR(err);
906 }
907 } else {
908 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 }
Al Virod0352d32010-06-06 21:51:16 -0400910
911 nd_set_link(nd, link);
912 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913}
914
Al Virod0352d32010-06-06 21:51:16 -0400915static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
916{
917 char *s = nd_get_link(nd);
918 if (!IS_ERR(s))
919 __putname(s);
920}
921
922static const struct inode_operations hostfs_link_iops = {
923 .readlink = generic_readlink,
924 .follow_link = hostfs_follow_link,
925 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926};
927
928static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
929{
930 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700931 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 int err;
933
934 sb->s_blocksize = 1024;
935 sb->s_blocksize_bits = 10;
936 sb->s_magic = HOSTFS_SUPER_MAGIC;
937 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400938 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700939 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800941 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700942 if (req_root == NULL)
943 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400946 sb->s_fs_info = host_root_path =
947 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700948 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 goto out;
950
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700951 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Al Viro52b209f72010-06-06 18:43:19 -0400953 root_inode = new_inode(sb);
954 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400955 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Al Viro4754b822010-06-06 20:33:12 -0400957 err = read_name(root_inode, host_root_path);
958 if (err)
959 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400960
Al Viro4754b822010-06-06 20:33:12 -0400961 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400962 char *name = follow_link(host_root_path);
963 if (IS_ERR(name))
964 err = PTR_ERR(name);
965 else
966 err = read_name(root_inode, name);
967 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400968 if (err)
969 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500973 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700974 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500975 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Jeff Dikef1adc052007-05-08 00:23:18 -0700977 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Jeff Dikef1adc052007-05-08 00:23:18 -0700979out_put:
980 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700981out:
982 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983}
984
Al Viro3c26ff62010-07-25 11:46:36 +0400985static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700986 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400987 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988{
Al Viro3c26ff62010-07-25 11:46:36 +0400989 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990}
991
Al Viro601d2c32010-06-06 17:53:01 -0400992static void hostfs_kill_sb(struct super_block *s)
993{
994 kill_anon_super(s);
995 kfree(s->s_fs_info);
996}
997
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998static struct file_system_type hostfs_type = {
999 .owner = THIS_MODULE,
1000 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001001 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -04001002 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 .fs_flags = 0,
1004};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -07001005MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
1007static int __init init_hostfs(void)
1008{
Jeff Dikef1adc052007-05-08 00:23:18 -07001009 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010}
1011
1012static void __exit exit_hostfs(void)
1013{
1014 unregister_filesystem(&hostfs_type);
1015}
1016
1017module_init(init_hostfs)
1018module_exit(exit_hostfs)
1019MODULE_LICENSE("GPL");