blob: 25437280a2071b8970efe6e394edb97a4433acd8 [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;
27};
28
29static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
30{
Jeff Dikef1adc052007-05-08 00:23:18 -070031 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070032}
33
Al Viro496ad9a2013-01-23 17:07:38 -050034#define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file))
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Nick Pigginfe15ce42011-01-07 17:49:23 +110036static int hostfs_d_delete(const struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070037{
Jeff Dikef1adc052007-05-08 00:23:18 -070038 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039}
40
Al Viroe16404e2009-02-20 05:55:13 +000041static const struct dentry_operations hostfs_dentry_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 .d_delete = hostfs_d_delete,
43};
44
45/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080046static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070047static int append = 0;
48
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080049static const struct inode_operations hostfs_iops;
50static const struct inode_operations hostfs_dir_iops;
Al Virod0352d32010-06-06 21:51:16 -040051static const struct inode_operations hostfs_link_iops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#ifndef MODULE
54static int __init hostfs_args(char *options, int *add)
55{
56 char *ptr;
57
58 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')
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 root_ino = options;
63
64 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070065 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070067 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070069 if (*options != '\0') {
70 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 append = 1;
72 else printf("hostfs_args - unsupported option - %s\n",
73 options);
74 }
75 options = ptr;
76 }
Jeff Dikef1adc052007-05-08 00:23:18 -070077 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
80__uml_setup("hostfs=", hostfs_args,
81"hostfs=<root dir>,<flags>,...\n"
82" This is used to set hostfs parameters. The root directory argument\n"
83" is used to confine all hostfs mounts to within the specified directory\n"
84" tree on the host. If this isn't specified, then a user inside UML can\n"
85" mount anything on the host that's accessible to the user that's running\n"
86" it.\n"
87" The only flag currently supported is 'append', which specifies that all\n"
88" files opened by hostfs will be opened in append mode.\n\n"
89);
90#endif
91
Al Viroe9193052010-06-06 23:16:34 -040092static char *__dentry_name(struct dentry *dentry, char *name)
93{
Nick Pigginec2447c2011-01-07 17:49:29 +110094 char *p = dentry_path_raw(dentry, name, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040095 char *root;
96 size_t len;
97
Al Viroe9193052010-06-06 23:16:34 -040098 root = dentry->d_sb->s_fs_info;
99 len = strlen(root);
100 if (IS_ERR(p)) {
101 __putname(name);
102 return NULL;
103 }
Al Viro850a4962010-08-18 06:18:57 -0400104 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -0400105 if (len > p - name) {
106 __putname(name);
107 return NULL;
108 }
109 if (p > name + len) {
110 char *s = name + len;
111 while ((*s++ = *p++) != '\0')
112 ;
113 }
114 return name;
115}
116
Al Viroc5322222010-06-06 20:42:10 -0400117static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118{
Al Viroe9193052010-06-06 23:16:34 -0400119 char *name = __getname();
120 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700121 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
James Hogan9dcc5e82013-03-27 10:47:12 +0000123 return __dentry_name(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124}
125
Al Viroc5322222010-06-06 20:42:10 -0400126static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
128 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100129 char *name;
130
131 dentry = d_find_alias(ino);
132 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400133 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Nick Pigginec2447c2011-01-07 17:49:29 +1100135 name = dentry_name(dentry);
136
137 dput(dentry);
138
139 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140}
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static char *follow_link(char *link)
143{
144 int len, n;
145 char *name, *resolved, *end;
146
147 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700148 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 n = -ENOMEM;
150 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700151 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 goto out;
153
WANG Congea7e7432008-11-19 15:36:46 -0800154 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700155 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 break;
157 len *= 2;
158 kfree(name);
159 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700160 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 goto out_free;
162
Jeff Dike84b3db02007-10-16 01:27:13 -0700163 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700164 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700167 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700168 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
170 *(end + 1) = '\0';
171 len = strlen(link) + strlen(name) + 1;
172
173 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700174 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 n = -ENOMEM;
176 goto out_free;
177 }
178
179 sprintf(resolved, "%s%s", link, name);
180 kfree(name);
181 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700182 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184 out_free:
185 kfree(name);
186 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700187 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188}
189
David Howells0a370e52008-02-07 00:15:50 -0800190static struct inode *hostfs_iget(struct super_block *sb)
191{
Al Viro52b209f72010-06-06 18:43:19 -0400192 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800193 if (!inode)
194 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800195 return inode;
196}
197
David Howells726c3342006-06-23 02:02:58 -0700198int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199{
Jeff Dike84b3db02007-10-16 01:27:13 -0700200 /*
201 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 * struct statfs still has 32-bit versions for most of these fields,
203 * so we convert them here
204 */
205 int err;
206 long long f_blocks;
207 long long f_bfree;
208 long long f_bavail;
209 long long f_files;
210 long long f_ffree;
211
Al Viro601d2c32010-06-06 17:53:01 -0400212 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
214 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700215 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700216 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700217 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 sf->f_blocks = f_blocks;
219 sf->f_bfree = f_bfree;
220 sf->f_bavail = f_bavail;
221 sf->f_files = f_files;
222 sf->f_ffree = f_ffree;
223 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700224 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225}
226
227static struct inode *hostfs_alloc_inode(struct super_block *sb)
228{
229 struct hostfs_inode_info *hi;
230
James Hogan371fdab2013-03-27 10:47:14 +0000231 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700232 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700233 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400234 hi->fd = -1;
James Hogan371fdab2013-03-27 10:47:14 +0000235 hi->mode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700237 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
239
Al Viroe971a6d2010-06-06 15:16:17 -0400240static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
Mark Fashehfef26652005-09-09 13:01:31 -0700242 truncate_inode_pages(&inode->i_data, 0);
Jan Karadbd57682012-05-03 14:48:02 +0200243 clear_inode(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700244 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 close_file(&HOSTFS_I(inode)->fd);
246 HOSTFS_I(inode)->fd = -1;
247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
249
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100250static void hostfs_i_callback(struct rcu_head *head)
251{
252 struct inode *inode = container_of(head, struct inode, i_rcu);
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100253 kfree(HOSTFS_I(inode));
254}
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256static void hostfs_destroy_inode(struct inode *inode)
257{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100258 call_rcu(&inode->i_rcu, hostfs_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259}
260
Al Viro34c80b12011-12-08 21:32:45 -0500261static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800262{
Al Viro34c80b12011-12-08 21:32:45 -0500263 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800264 size_t offset = strlen(root_ino) + 1;
265
266 if (strlen(root_path) > offset)
267 seq_printf(seq, ",%s", root_path + offset);
268
269 return 0;
270}
271
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800272static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400275 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800277 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278};
279
Al Viro8e28bc72013-05-22 16:34:19 -0400280int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
282 void *dir;
283 char *name;
284 unsigned long long next, ino;
285 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100286 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Al Viroc5322222010-06-06 20:42:10 -0400288 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700289 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700290 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400292 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700293 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700294 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400295 next = ctx->pos;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100296 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400297 if (!dir_emit(ctx, name, len, ino, type))
298 break;
299 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700302 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303}
304
305int hostfs_file_open(struct inode *ino, struct file *file)
306{
Al Virof8ad8502010-06-06 23:49:18 -0400307 static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400309 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400310 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400311 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700314 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700315 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Al Virof8ad8502010-06-06 23:49:18 -0400317 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Al Virof8ad8502010-06-06 23:49:18 -0400319retry:
320 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400322 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700324 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 r = 1;
326
Al Viroc5322222010-06-06 20:42:10 -0400327 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700328 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700329 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400332 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700333 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700334 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400335
336 mutex_lock(&open_mutex);
337 /* somebody else had handled it first? */
338 if ((mode & HOSTFS_I(ino)->mode) == mode) {
339 mutex_unlock(&open_mutex);
340 return 0;
341 }
342 if ((mode | HOSTFS_I(ino)->mode) != mode) {
343 mode |= HOSTFS_I(ino)->mode;
344 mutex_unlock(&open_mutex);
345 close_file(&fd);
346 goto retry;
347 }
348 if (HOSTFS_I(ino)->fd == -1) {
349 HOSTFS_I(ino)->fd = fd;
350 } else {
351 err = replace_file(fd, HOSTFS_I(ino)->fd);
352 close_file(&fd);
353 if (err < 0) {
354 mutex_unlock(&open_mutex);
355 return err;
356 }
357 }
358 HOSTFS_I(ino)->mode = mode;
359 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Jeff Dikef1adc052007-05-08 00:23:18 -0700361 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
Richard Weinberger65984ff2013-08-04 17:23:51 +0000364static int hostfs_file_release(struct inode *inode, struct file *file)
365{
366 filemap_write_and_wait(inode->i_mapping);
367
368 return 0;
369}
370
Josef Bacik02c24a82011-07-16 20:44:56 -0400371int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
Josef Bacik02c24a82011-07-16 20:44:56 -0400373 struct inode *inode = file->f_mapping->host;
374 int ret;
375
376 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
377 if (ret)
378 return ret;
379
380 mutex_lock(&inode->i_mutex);
381 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
382 mutex_unlock(&inode->i_mutex);
383
384 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800387static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700389 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200390 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 .aio_read = generic_file_aio_read,
392 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700393 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .mmap = generic_file_mmap,
395 .open = hostfs_file_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000396 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 .fsync = hostfs_fsync,
398};
399
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800400static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 .llseek = generic_file_llseek,
Al Viro8e28bc72013-05-22 16:34:19 -0400402 .iterate = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 .read = generic_read_dir,
404};
405
406int hostfs_writepage(struct page *page, struct writeback_control *wbc)
407{
408 struct address_space *mapping = page->mapping;
409 struct inode *inode = mapping->host;
410 char *buffer;
411 unsigned long long base;
412 int count = PAGE_CACHE_SIZE;
413 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
414 int err;
415
416 if (page->index >= end_index)
417 count = inode->i_size & (PAGE_CACHE_SIZE-1);
418
419 buffer = kmap(page);
420 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
421
422 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700423 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 ClearPageUptodate(page);
425 goto out;
426 }
427
428 if (base > inode->i_size)
429 inode->i_size = base;
430
431 if (PageError(page))
432 ClearPageError(page);
433 err = 0;
434
435 out:
436 kunmap(page);
437
438 unlock_page(page);
439 return err;
440}
441
442int hostfs_readpage(struct file *file, struct page *page)
443{
444 char *buffer;
445 long long start;
446 int err = 0;
447
448 start = (long long) page->index << PAGE_CACHE_SHIFT;
449 buffer = kmap(page);
450 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
451 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700452 if (err < 0)
453 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
456
457 flush_dcache_page(page);
458 SetPageUptodate(page);
459 if (PageError(page)) ClearPageError(page);
460 err = 0;
461 out:
462 kunmap(page);
463 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700464 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465}
466
Nick Pigginae361ff2007-10-16 01:25:17 -0700467int hostfs_write_begin(struct file *file, struct address_space *mapping,
468 loff_t pos, unsigned len, unsigned flags,
469 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
Nick Pigginae361ff2007-10-16 01:25:17 -0700471 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Nick Piggin54566b22009-01-04 12:00:53 -0800473 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700474 if (!*pagep)
475 return -ENOMEM;
476 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477}
478
Nick Pigginae361ff2007-10-16 01:25:17 -0700479int hostfs_write_end(struct file *file, struct address_space *mapping,
480 loff_t pos, unsigned len, unsigned copied,
481 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700484 void *buffer;
485 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
486 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700489 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700491
492 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
493 SetPageUptodate(page);
494
Jeff Dike84b3db02007-10-16 01:27:13 -0700495 /*
496 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700497 * i_size against the last byte written.
498 */
499 if (err > 0 && (pos > inode->i_size))
500 inode->i_size = pos;
501 unlock_page(page);
502 page_cache_release(page);
503
Jeff Dikef1adc052007-05-08 00:23:18 -0700504 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505}
506
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700507static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 .writepage = hostfs_writepage,
509 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700510 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700511 .write_begin = hostfs_write_begin,
512 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513};
514
Al Viro4754b822010-06-06 20:33:12 -0400515static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
Al Viro4754b822010-06-06 20:33:12 -0400517 dev_t rdev;
518 struct hostfs_stat st;
519 int err = stat_file(name, &st, -1);
520 if (err)
521 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Al Viro5e2df282010-06-06 19:38:18 -0400523 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400524 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Al Viro4754b822010-06-06 20:33:12 -0400526 switch (st.mode & S_IFMT) {
527 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400528 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400529 break;
530 case S_IFDIR:
531 ino->i_op = &hostfs_dir_iops;
532 ino->i_fop = &hostfs_dir_fops;
533 break;
534 case S_IFCHR:
535 case S_IFBLK:
536 case S_IFIFO:
537 case S_IFSOCK:
538 init_special_inode(ino, st.mode & S_IFMT, rdev);
539 ino->i_op = &hostfs_iops;
540 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Al Viro4754b822010-06-06 20:33:12 -0400542 default:
543 ino->i_op = &hostfs_iops;
544 ino->i_fop = &hostfs_file_fops;
545 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 }
Al Viro4754b822010-06-06 20:33:12 -0400547
548 ino->i_ino = st.ino;
549 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200550 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800551 i_uid_write(ino, st.uid);
552 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400553 ino->i_atime = st.atime;
554 ino->i_mtime = st.mtime;
555 ino->i_ctime = st.ctime;
556 ino->i_size = st.size;
557 ino->i_blocks = st.blocks;
558 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}
560
Al Viro4acdaf22011-07-26 01:42:34 -0400561int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400562 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
564 struct inode *inode;
565 char *name;
566 int error, fd;
567
David Howells0a370e52008-02-07 00:15:50 -0800568 inode = hostfs_iget(dir->i_sb);
569 if (IS_ERR(inode)) {
570 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700571 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400575 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700576 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 goto out_put;
578
579 fd = file_create(name,
580 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
581 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
582 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400583 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400585 else
Al Viro5e2df282010-06-06 19:38:18 -0400586 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Al Viroe9193052010-06-06 23:16:34 -0400588 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700589 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 goto out_put;
591
592 HOSTFS_I(inode)->fd = fd;
593 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
594 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700595 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
597 out_put:
598 iput(inode);
599 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700600 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
603struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Al Viro00cd8dd2012-06-10 17:13:09 -0400604 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
606 struct inode *inode;
607 char *name;
608 int err;
609
David Howells0a370e52008-02-07 00:15:50 -0800610 inode = hostfs_iget(ino->i_sb);
611 if (IS_ERR(inode)) {
612 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400617 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700618 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 goto out_put;
620
621 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400622
Al Viroe9193052010-06-06 23:16:34 -0400623 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700624 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 iput(inode);
626 inode = NULL;
627 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700628 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 goto out_put;
630
631 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700632 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634 out_put:
635 iput(inode);
636 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700637 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638}
639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
641{
Jeff Dikef1adc052007-05-08 00:23:18 -0700642 char *from_name, *to_name;
643 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Al Viroc5322222010-06-06 20:42:10 -0400645 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700646 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400647 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700648 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400649 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700650 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700652 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400653 __putname(from_name);
654 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
657
658int hostfs_unlink(struct inode *ino, struct dentry *dentry)
659{
660 char *file;
661 int err;
662
Jeff Dike84b3db02007-10-16 01:27:13 -0700663 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700664 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Al Virof8d7e182010-06-06 23:19:04 -0400666 if ((file = dentry_name(dentry)) == NULL)
667 return -ENOMEM;
668
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400670 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700671 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672}
673
674int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
675{
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
Al Viro18bb1db2011-07-26 01:41:39 -0400686int 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
698int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
699{
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
750int hostfs_rename(struct inode *from_ino, struct dentry *from,
751 struct inode *to_ino, struct dentry *to)
752{
753 char *from_name, *to_name;
754 int err;
755
Al Viroc5322222010-06-06 20:42:10 -0400756 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700757 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400758 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400759 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700760 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 }
762 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400763 __putname(from_name);
764 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700765 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766}
767
Al Viro10556cb2011-06-20 19:28:19 -0400768int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
770 char *name;
771 int r = 0, w = 0, x = 0, err;
772
Al Viro10556cb2011-06-20 19:28:19 -0400773 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100774 return -ECHILD;
775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 if (desired & MAY_READ) r = 1;
777 if (desired & MAY_WRITE) w = 1;
778 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400779 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700780 if (name == NULL)
781 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700784 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 err = 0;
786 else
787 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400788 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700789 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400790 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 return err;
792}
793
794int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
795{
Christoph Hellwig10257742010-06-04 11:30:02 +0200796 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 struct hostfs_iattr attrs;
798 char *name;
799 int err;
800
Christoph Hellwig10257742010-06-04 11:30:02 +0200801 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700802
Christoph Hellwig10257742010-06-04 11:30:02 +0200803 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 if (err)
805 return err;
806
Jeff Dike84b3db02007-10-16 01:27:13 -0700807 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 attr->ia_valid &= ~ATTR_SIZE;
809
810 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700811 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 attrs.ia_valid |= HOSTFS_ATTR_MODE;
813 attrs.ia_mode = attr->ia_mode;
814 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700815 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800817 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700819 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800821 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700823 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
825 attrs.ia_size = attr->ia_size;
826 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700827 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
829 attrs.ia_atime = attr->ia_atime;
830 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700831 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
833 attrs.ia_mtime = attr->ia_mtime;
834 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700835 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
837 attrs.ia_ctime = attr->ia_ctime;
838 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
841 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700842 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
844 }
Al Viroc5322222010-06-06 20:42:10 -0400845 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700846 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700847 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700848 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400849 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700850 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700851 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Christoph Hellwig10257742010-06-04 11:30:02 +0200853 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200854 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200855 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200856
857 setattr_copy(inode, attr);
858 mark_inode_dirty(inode);
859 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800862static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 .permission = hostfs_permission,
864 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865};
866
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800867static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 .create = hostfs_create,
869 .lookup = hostfs_lookup,
870 .link = hostfs_link,
871 .unlink = hostfs_unlink,
872 .symlink = hostfs_symlink,
873 .mkdir = hostfs_mkdir,
874 .rmdir = hostfs_rmdir,
875 .mknod = hostfs_mknod,
876 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 .permission = hostfs_permission,
878 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879};
880
Al Virod0352d32010-06-06 21:51:16 -0400881static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882{
Al Virod0352d32010-06-06 21:51:16 -0400883 char *link = __getname();
884 if (link) {
885 char *path = dentry_name(dentry);
886 int err = -ENOMEM;
887 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400888 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400889 if (err == PATH_MAX)
890 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400891 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400892 }
893 if (err < 0) {
894 __putname(link);
895 link = ERR_PTR(err);
896 }
897 } else {
898 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 }
Al Virod0352d32010-06-06 21:51:16 -0400900
901 nd_set_link(nd, link);
902 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903}
904
Al Virod0352d32010-06-06 21:51:16 -0400905static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
906{
907 char *s = nd_get_link(nd);
908 if (!IS_ERR(s))
909 __putname(s);
910}
911
912static const struct inode_operations hostfs_link_iops = {
913 .readlink = generic_readlink,
914 .follow_link = hostfs_follow_link,
915 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916};
917
918static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
919{
920 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700921 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 int err;
923
924 sb->s_blocksize = 1024;
925 sb->s_blocksize_bits = 10;
926 sb->s_magic = HOSTFS_SUPER_MAGIC;
927 sb->s_op = &hostfs_sbops;
Al Virof772c4a2011-01-12 16:47:00 -0500928 sb->s_d_op = &hostfs_dentry_ops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700929 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800931 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700932 if (req_root == NULL)
933 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
935 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400936 sb->s_fs_info = host_root_path =
937 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700938 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 goto out;
940
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700941 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Al Viro52b209f72010-06-06 18:43:19 -0400943 root_inode = new_inode(sb);
944 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400945 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
Al Viro4754b822010-06-06 20:33:12 -0400947 err = read_name(root_inode, host_root_path);
948 if (err)
949 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400950
Al Viro4754b822010-06-06 20:33:12 -0400951 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400952 char *name = follow_link(host_root_path);
953 if (IS_ERR(name))
954 err = PTR_ERR(name);
955 else
956 err = read_name(root_inode, name);
957 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400958 if (err)
959 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500963 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700964 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500965 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Jeff Dikef1adc052007-05-08 00:23:18 -0700967 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Jeff Dikef1adc052007-05-08 00:23:18 -0700969out_put:
970 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700971out:
972 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973}
974
Al Viro3c26ff62010-07-25 11:46:36 +0400975static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700976 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400977 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978{
Al Viro3c26ff62010-07-25 11:46:36 +0400979 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
981
Al Viro601d2c32010-06-06 17:53:01 -0400982static void hostfs_kill_sb(struct super_block *s)
983{
984 kill_anon_super(s);
985 kfree(s->s_fs_info);
986}
987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988static struct file_system_type hostfs_type = {
989 .owner = THIS_MODULE,
990 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400991 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400992 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 .fs_flags = 0,
994};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700995MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
997static int __init init_hostfs(void)
998{
Jeff Dikef1adc052007-05-08 00:23:18 -0700999 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000}
1001
1002static void __exit exit_hostfs(void)
1003{
1004 unregister_filesystem(&hostfs_type);
1005}
1006
1007module_init(init_hostfs)
1008module_exit(exit_hostfs)
1009MODULE_LICENSE("GPL");