blob: cddb0521751278526dfc1b678acbf708a906a815 [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
Josef Bacik02c24a82011-07-16 20:44:56 -0400364int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Josef Bacik02c24a82011-07-16 20:44:56 -0400366 struct inode *inode = file->f_mapping->host;
367 int ret;
368
369 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
370 if (ret)
371 return ret;
372
373 mutex_lock(&inode->i_mutex);
374 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
375 mutex_unlock(&inode->i_mutex);
376
377 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378}
379
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800380static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700382 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200383 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 .aio_read = generic_file_aio_read,
385 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700386 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 .mmap = generic_file_mmap,
388 .open = hostfs_file_open,
389 .release = NULL,
390 .fsync = hostfs_fsync,
391};
392
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800393static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .llseek = generic_file_llseek,
Al Viro8e28bc72013-05-22 16:34:19 -0400395 .iterate = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 .read = generic_read_dir,
397};
398
399int hostfs_writepage(struct page *page, struct writeback_control *wbc)
400{
401 struct address_space *mapping = page->mapping;
402 struct inode *inode = mapping->host;
403 char *buffer;
404 unsigned long long base;
405 int count = PAGE_CACHE_SIZE;
406 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
407 int err;
408
409 if (page->index >= end_index)
410 count = inode->i_size & (PAGE_CACHE_SIZE-1);
411
412 buffer = kmap(page);
413 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
414
415 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700416 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 ClearPageUptodate(page);
418 goto out;
419 }
420
421 if (base > inode->i_size)
422 inode->i_size = base;
423
424 if (PageError(page))
425 ClearPageError(page);
426 err = 0;
427
428 out:
429 kunmap(page);
430
431 unlock_page(page);
432 return err;
433}
434
435int hostfs_readpage(struct file *file, struct page *page)
436{
437 char *buffer;
438 long long start;
439 int err = 0;
440
441 start = (long long) page->index << PAGE_CACHE_SHIFT;
442 buffer = kmap(page);
443 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
444 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700445 if (err < 0)
446 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
449
450 flush_dcache_page(page);
451 SetPageUptodate(page);
452 if (PageError(page)) ClearPageError(page);
453 err = 0;
454 out:
455 kunmap(page);
456 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700457 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
Nick Pigginae361ff2007-10-16 01:25:17 -0700460int hostfs_write_begin(struct file *file, struct address_space *mapping,
461 loff_t pos, unsigned len, unsigned flags,
462 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
Nick Pigginae361ff2007-10-16 01:25:17 -0700464 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Nick Piggin54566b22009-01-04 12:00:53 -0800466 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700467 if (!*pagep)
468 return -ENOMEM;
469 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470}
471
Nick Pigginae361ff2007-10-16 01:25:17 -0700472int hostfs_write_end(struct file *file, struct address_space *mapping,
473 loff_t pos, unsigned len, unsigned copied,
474 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700477 void *buffer;
478 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
479 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700482 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700484
485 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
486 SetPageUptodate(page);
487
Jeff Dike84b3db02007-10-16 01:27:13 -0700488 /*
489 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700490 * i_size against the last byte written.
491 */
492 if (err > 0 && (pos > inode->i_size))
493 inode->i_size = pos;
494 unlock_page(page);
495 page_cache_release(page);
496
Jeff Dikef1adc052007-05-08 00:23:18 -0700497 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700500static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 .writepage = hostfs_writepage,
502 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700503 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700504 .write_begin = hostfs_write_begin,
505 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506};
507
Al Viro4754b822010-06-06 20:33:12 -0400508static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
Al Viro4754b822010-06-06 20:33:12 -0400510 dev_t rdev;
511 struct hostfs_stat st;
512 int err = stat_file(name, &st, -1);
513 if (err)
514 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Al Viro5e2df282010-06-06 19:38:18 -0400516 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400517 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Al Viro4754b822010-06-06 20:33:12 -0400519 switch (st.mode & S_IFMT) {
520 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400521 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400522 break;
523 case S_IFDIR:
524 ino->i_op = &hostfs_dir_iops;
525 ino->i_fop = &hostfs_dir_fops;
526 break;
527 case S_IFCHR:
528 case S_IFBLK:
529 case S_IFIFO:
530 case S_IFSOCK:
531 init_special_inode(ino, st.mode & S_IFMT, rdev);
532 ino->i_op = &hostfs_iops;
533 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Al Viro4754b822010-06-06 20:33:12 -0400535 default:
536 ino->i_op = &hostfs_iops;
537 ino->i_fop = &hostfs_file_fops;
538 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
Al Viro4754b822010-06-06 20:33:12 -0400540
541 ino->i_ino = st.ino;
542 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200543 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800544 i_uid_write(ino, st.uid);
545 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400546 ino->i_atime = st.atime;
547 ino->i_mtime = st.mtime;
548 ino->i_ctime = st.ctime;
549 ino->i_size = st.size;
550 ino->i_blocks = st.blocks;
551 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552}
553
Al Viro4acdaf22011-07-26 01:42:34 -0400554int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400555 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{
557 struct inode *inode;
558 char *name;
559 int error, fd;
560
David Howells0a370e52008-02-07 00:15:50 -0800561 inode = hostfs_iget(dir->i_sb);
562 if (IS_ERR(inode)) {
563 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700564 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400568 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700569 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 goto out_put;
571
572 fd = file_create(name,
573 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
574 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
575 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400576 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400578 else
Al Viro5e2df282010-06-06 19:38:18 -0400579 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Al Viroe9193052010-06-06 23:16:34 -0400581 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700582 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 goto out_put;
584
585 HOSTFS_I(inode)->fd = fd;
586 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
587 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700588 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
590 out_put:
591 iput(inode);
592 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700593 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594}
595
596struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Al Viro00cd8dd2012-06-10 17:13:09 -0400597 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598{
599 struct inode *inode;
600 char *name;
601 int err;
602
David Howells0a370e52008-02-07 00:15:50 -0800603 inode = hostfs_iget(ino->i_sb);
604 if (IS_ERR(inode)) {
605 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400610 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700611 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto out_put;
613
614 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400615
Al Viroe9193052010-06-06 23:16:34 -0400616 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700617 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 iput(inode);
619 inode = NULL;
620 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700621 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 goto out_put;
623
624 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700625 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
627 out_put:
628 iput(inode);
629 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700630 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
634{
Jeff Dikef1adc052007-05-08 00:23:18 -0700635 char *from_name, *to_name;
636 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Al Viroc5322222010-06-06 20:42:10 -0400638 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400640 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700641 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400642 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700643 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700645 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400646 __putname(from_name);
647 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700648 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649}
650
651int hostfs_unlink(struct inode *ino, struct dentry *dentry)
652{
653 char *file;
654 int err;
655
Jeff Dike84b3db02007-10-16 01:27:13 -0700656 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700657 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Al Virof8d7e182010-06-06 23:19:04 -0400659 if ((file = dentry_name(dentry)) == NULL)
660 return -ENOMEM;
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400663 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700664 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665}
666
667int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
668{
669 char *file;
670 int err;
671
Al Viroc5322222010-06-06 20:42:10 -0400672 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700673 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400675 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677}
678
Al Viro18bb1db2011-07-26 01:41:39 -0400679int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 char *file;
682 int err;
683
Al Viroc5322222010-06-06 20:42:10 -0400684 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700685 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400687 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689}
690
691int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
692{
693 char *file;
694 int err;
695
Al Viroc5322222010-06-06 20:42:10 -0400696 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700697 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400699 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700700 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701}
702
Al Viro1a67aaf2011-07-26 01:52:52 -0400703static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
705 struct inode *inode;
706 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800707 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
David Howells0a370e52008-02-07 00:15:50 -0800709 inode = hostfs_iget(dir->i_sb);
710 if (IS_ERR(inode)) {
711 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400716 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700717 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 goto out_put;
719
720 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800721 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400722 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 goto out_free;
724
725 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400726 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400727 if (err)
728 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700729 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 goto out_put;
731
732 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700733 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400736 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 out_put:
738 iput(inode);
739 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700740 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741}
742
743int hostfs_rename(struct inode *from_ino, struct dentry *from,
744 struct inode *to_ino, struct dentry *to)
745{
746 char *from_name, *to_name;
747 int err;
748
Al Viroc5322222010-06-06 20:42:10 -0400749 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700750 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400751 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400752 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700753 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 }
755 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400756 __putname(from_name);
757 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700758 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759}
760
Al Viro10556cb2011-06-20 19:28:19 -0400761int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 char *name;
764 int r = 0, w = 0, x = 0, err;
765
Al Viro10556cb2011-06-20 19:28:19 -0400766 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100767 return -ECHILD;
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 if (desired & MAY_READ) r = 1;
770 if (desired & MAY_WRITE) w = 1;
771 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400772 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700773 if (name == NULL)
774 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
776 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700777 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 err = 0;
779 else
780 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400781 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700782 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400783 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 return err;
785}
786
787int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
788{
Christoph Hellwig10257742010-06-04 11:30:02 +0200789 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 struct hostfs_iattr attrs;
791 char *name;
792 int err;
793
Christoph Hellwig10257742010-06-04 11:30:02 +0200794 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700795
Christoph Hellwig10257742010-06-04 11:30:02 +0200796 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if (err)
798 return err;
799
Jeff Dike84b3db02007-10-16 01:27:13 -0700800 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 attr->ia_valid &= ~ATTR_SIZE;
802
803 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700804 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 attrs.ia_valid |= HOSTFS_ATTR_MODE;
806 attrs.ia_mode = attr->ia_mode;
807 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700808 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800810 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700812 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800814 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700816 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
818 attrs.ia_size = attr->ia_size;
819 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700820 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
822 attrs.ia_atime = attr->ia_atime;
823 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700824 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
826 attrs.ia_mtime = attr->ia_mtime;
827 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700828 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
830 attrs.ia_ctime = attr->ia_ctime;
831 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700832 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
834 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700835 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
837 }
Al Viroc5322222010-06-06 20:42:10 -0400838 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700840 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700841 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400842 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700843 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700844 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Christoph Hellwig10257742010-06-04 11:30:02 +0200846 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200847 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200848 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200849
850 setattr_copy(inode, attr);
851 mark_inode_dirty(inode);
852 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853}
854
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800855static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 .permission = hostfs_permission,
857 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858};
859
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800860static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 .create = hostfs_create,
862 .lookup = hostfs_lookup,
863 .link = hostfs_link,
864 .unlink = hostfs_unlink,
865 .symlink = hostfs_symlink,
866 .mkdir = hostfs_mkdir,
867 .rmdir = hostfs_rmdir,
868 .mknod = hostfs_mknod,
869 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 .permission = hostfs_permission,
871 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872};
873
Al Virod0352d32010-06-06 21:51:16 -0400874static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
Al Virod0352d32010-06-06 21:51:16 -0400876 char *link = __getname();
877 if (link) {
878 char *path = dentry_name(dentry);
879 int err = -ENOMEM;
880 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400881 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400882 if (err == PATH_MAX)
883 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400884 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400885 }
886 if (err < 0) {
887 __putname(link);
888 link = ERR_PTR(err);
889 }
890 } else {
891 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 }
Al Virod0352d32010-06-06 21:51:16 -0400893
894 nd_set_link(nd, link);
895 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896}
897
Al Virod0352d32010-06-06 21:51:16 -0400898static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
899{
900 char *s = nd_get_link(nd);
901 if (!IS_ERR(s))
902 __putname(s);
903}
904
905static const struct inode_operations hostfs_link_iops = {
906 .readlink = generic_readlink,
907 .follow_link = hostfs_follow_link,
908 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909};
910
911static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
912{
913 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700914 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 int err;
916
917 sb->s_blocksize = 1024;
918 sb->s_blocksize_bits = 10;
919 sb->s_magic = HOSTFS_SUPER_MAGIC;
920 sb->s_op = &hostfs_sbops;
Al Virof772c4a2011-01-12 16:47:00 -0500921 sb->s_d_op = &hostfs_dentry_ops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700922 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800924 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700925 if (req_root == NULL)
926 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400929 sb->s_fs_info = host_root_path =
930 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700931 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 goto out;
933
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700934 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Al Viro52b209f72010-06-06 18:43:19 -0400936 root_inode = new_inode(sb);
937 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400938 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Al Viro4754b822010-06-06 20:33:12 -0400940 err = read_name(root_inode, host_root_path);
941 if (err)
942 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400943
Al Viro4754b822010-06-06 20:33:12 -0400944 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400945 char *name = follow_link(host_root_path);
946 if (IS_ERR(name))
947 err = PTR_ERR(name);
948 else
949 err = read_name(root_inode, name);
950 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400951 if (err)
952 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500956 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700957 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500958 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Jeff Dikef1adc052007-05-08 00:23:18 -0700960 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Jeff Dikef1adc052007-05-08 00:23:18 -0700962out_put:
963 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700964out:
965 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
Al Viro3c26ff62010-07-25 11:46:36 +0400968static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700969 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400970 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
Al Viro3c26ff62010-07-25 11:46:36 +0400972 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973}
974
Al Viro601d2c32010-06-06 17:53:01 -0400975static void hostfs_kill_sb(struct super_block *s)
976{
977 kill_anon_super(s);
978 kfree(s->s_fs_info);
979}
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981static struct file_system_type hostfs_type = {
982 .owner = THIS_MODULE,
983 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400984 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400985 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 .fs_flags = 0,
987};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700988MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990static int __init init_hostfs(void)
991{
Jeff Dikef1adc052007-05-08 00:23:18 -0700992 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993}
994
995static void __exit exit_hostfs(void)
996{
997 unregister_filesystem(&hostfs_type);
998}
999
1000module_init(init_hostfs)
1001module_exit(exit_hostfs)
1002MODULE_LICENSE("GPL");