blob: 457addc5c91f2f2da42092d9f193a47aa8f678dd [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/module.h>
Jeff Dike84b3db02007-10-16 01:27:13 -070011#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/statfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -080015#include <linux/seq_file.h>
Jiri Kosina6966a972008-02-09 00:10:14 -080016#include <linux/mount.h>
Al Virod0352d32010-06-06 21:51:16 -040017#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "hostfs.h"
Al Viro37185b32012-10-08 03:27:32 +010019#include <init.h>
20#include <kern.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22struct hostfs_inode_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 int fd;
Al Viroaeb5d722008-09-02 15:28:45 -040024 fmode_t mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 struct inode vfs_inode;
26};
27
28static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
29{
Jeff Dikef1adc052007-05-08 00:23:18 -070030 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031}
32
Josef Sipek680b0da2006-12-08 02:37:05 -080033#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Nick Pigginfe15ce42011-01-07 17:49:23 +110035static int hostfs_d_delete(const struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070036{
Jeff Dikef1adc052007-05-08 00:23:18 -070037 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038}
39
Al Viroe16404e2009-02-20 05:55:13 +000040static const struct dentry_operations hostfs_dentry_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 .d_delete = hostfs_d_delete,
42};
43
44/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080045static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070046static int append = 0;
47
48#define HOSTFS_SUPER_MAGIC 0x00c0ffee
49
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080050static const struct inode_operations hostfs_iops;
51static const struct inode_operations hostfs_dir_iops;
Al Virod0352d32010-06-06 21:51:16 -040052static const struct inode_operations hostfs_link_iops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54#ifndef MODULE
55static int __init hostfs_args(char *options, int *add)
56{
57 char *ptr;
58
59 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070060 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070062 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 root_ino = options;
64
65 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070066 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070068 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070070 if (*options != '\0') {
71 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 append = 1;
73 else printf("hostfs_args - unsupported option - %s\n",
74 options);
75 }
76 options = ptr;
77 }
Jeff Dikef1adc052007-05-08 00:23:18 -070078 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079}
80
81__uml_setup("hostfs=", hostfs_args,
82"hostfs=<root dir>,<flags>,...\n"
83" This is used to set hostfs parameters. The root directory argument\n"
84" is used to confine all hostfs mounts to within the specified directory\n"
85" tree on the host. If this isn't specified, then a user inside UML can\n"
86" mount anything on the host that's accessible to the user that's running\n"
87" it.\n"
88" The only flag currently supported is 'append', which specifies that all\n"
89" files opened by hostfs will be opened in append mode.\n\n"
90);
91#endif
92
Al Viroe9193052010-06-06 23:16:34 -040093static char *__dentry_name(struct dentry *dentry, char *name)
94{
Nick Pigginec2447c2011-01-07 17:49:29 +110095 char *p = dentry_path_raw(dentry, name, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040096 char *root;
97 size_t len;
98
Al Viroe9193052010-06-06 23:16:34 -040099 root = dentry->d_sb->s_fs_info;
100 len = strlen(root);
101 if (IS_ERR(p)) {
102 __putname(name);
103 return NULL;
104 }
Al Viro850a4962010-08-18 06:18:57 -0400105 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -0400106 if (len > p - name) {
107 __putname(name);
108 return NULL;
109 }
110 if (p > name + len) {
111 char *s = name + len;
112 while ((*s++ = *p++) != '\0')
113 ;
114 }
115 return name;
116}
117
Al Viroc5322222010-06-06 20:42:10 -0400118static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119{
Al Viroe9193052010-06-06 23:16:34 -0400120 char *name = __getname();
121 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700122 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Al Viroe9193052010-06-06 23:16:34 -0400124 return __dentry_name(dentry, name); /* will unlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
Al Viroc5322222010-06-06 20:42:10 -0400127static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
129 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100130 char *name;
131
132 dentry = d_find_alias(ino);
133 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400134 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Nick Pigginec2447c2011-01-07 17:49:29 +1100136 name = dentry_name(dentry);
137
138 dput(dentry);
139
140 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141}
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static char *follow_link(char *link)
144{
145 int len, n;
146 char *name, *resolved, *end;
147
148 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700149 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 n = -ENOMEM;
151 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700152 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 goto out;
154
WANG Congea7e7432008-11-19 15:36:46 -0800155 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700156 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 break;
158 len *= 2;
159 kfree(name);
160 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700161 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 goto out_free;
163
Jeff Dike84b3db02007-10-16 01:27:13 -0700164 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700165 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700168 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700169 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171 *(end + 1) = '\0';
172 len = strlen(link) + strlen(name) + 1;
173
174 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700175 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 n = -ENOMEM;
177 goto out_free;
178 }
179
180 sprintf(resolved, "%s%s", link, name);
181 kfree(name);
182 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700183 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185 out_free:
186 kfree(name);
187 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700188 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189}
190
David Howells0a370e52008-02-07 00:15:50 -0800191static struct inode *hostfs_iget(struct super_block *sb)
192{
Al Viro52b209f2010-06-06 18:43:19 -0400193 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800194 if (!inode)
195 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800196 return inode;
197}
198
David Howells726c3342006-06-23 02:02:58 -0700199int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
Jeff Dike84b3db02007-10-16 01:27:13 -0700201 /*
202 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 * struct statfs still has 32-bit versions for most of these fields,
204 * so we convert them here
205 */
206 int err;
207 long long f_blocks;
208 long long f_bfree;
209 long long f_bavail;
210 long long f_files;
211 long long f_ffree;
212
Al Viro601d2c32010-06-06 17:53:01 -0400213 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
215 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700216 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700217 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700218 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 sf->f_blocks = f_blocks;
220 sf->f_bfree = f_bfree;
221 sf->f_bavail = f_bavail;
222 sf->f_files = f_files;
223 sf->f_ffree = f_ffree;
224 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700225 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
228static struct inode *hostfs_alloc_inode(struct super_block *sb)
229{
230 struct hostfs_inode_info *hi;
231
Al Viro601d2c32010-06-06 17:53:01 -0400232 hi = kzalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700233 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700234 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400235 hi->fd = -1;
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
280int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
281{
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 next = file->f_pos;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100296 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 error = (*filldir)(ent, name, len, file->f_pos,
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100298 ino, type);
Jeff Dike84b3db02007-10-16 01:27:13 -0700299 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 file->f_pos = next;
301 }
302 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700303 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304}
305
306int hostfs_file_open(struct inode *ino, struct file *file)
307{
Al Virof8ad8502010-06-06 23:49:18 -0400308 static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400310 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400311 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400312 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700315 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700316 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Al Virof8ad8502010-06-06 23:49:18 -0400318 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Al Virof8ad8502010-06-06 23:49:18 -0400320retry:
321 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400323 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700325 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 r = 1;
327
Al Viroc5322222010-06-06 20:42:10 -0400328 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700329 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700330 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400333 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700334 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700335 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400336
337 mutex_lock(&open_mutex);
338 /* somebody else had handled it first? */
339 if ((mode & HOSTFS_I(ino)->mode) == mode) {
340 mutex_unlock(&open_mutex);
341 return 0;
342 }
343 if ((mode | HOSTFS_I(ino)->mode) != mode) {
344 mode |= HOSTFS_I(ino)->mode;
345 mutex_unlock(&open_mutex);
346 close_file(&fd);
347 goto retry;
348 }
349 if (HOSTFS_I(ino)->fd == -1) {
350 HOSTFS_I(ino)->fd = fd;
351 } else {
352 err = replace_file(fd, HOSTFS_I(ino)->fd);
353 close_file(&fd);
354 if (err < 0) {
355 mutex_unlock(&open_mutex);
356 return err;
357 }
358 }
359 HOSTFS_I(ino)->mode = mode;
360 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Jeff Dikef1adc052007-05-08 00:23:18 -0700362 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
364
Josef Bacik02c24a82011-07-16 20:44:56 -0400365int hostfs_fsync(struct file *file, loff_t start, loff_t end, 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,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700383 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200384 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 .aio_read = generic_file_aio_read,
386 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700387 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 .mmap = generic_file_mmap,
389 .open = hostfs_file_open,
390 .release = NULL,
391 .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,
396 .readdir = hostfs_readdir,
397 .read = generic_read_dir,
398};
399
400int hostfs_writepage(struct page *page, struct writeback_control *wbc)
401{
402 struct address_space *mapping = page->mapping;
403 struct inode *inode = mapping->host;
404 char *buffer;
405 unsigned long long base;
406 int count = PAGE_CACHE_SIZE;
407 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
408 int err;
409
410 if (page->index >= end_index)
411 count = inode->i_size & (PAGE_CACHE_SIZE-1);
412
413 buffer = kmap(page);
414 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
415
416 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700417 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 ClearPageUptodate(page);
419 goto out;
420 }
421
422 if (base > inode->i_size)
423 inode->i_size = base;
424
425 if (PageError(page))
426 ClearPageError(page);
427 err = 0;
428
429 out:
430 kunmap(page);
431
432 unlock_page(page);
433 return err;
434}
435
436int hostfs_readpage(struct file *file, struct page *page)
437{
438 char *buffer;
439 long long start;
440 int err = 0;
441
442 start = (long long) page->index << PAGE_CACHE_SHIFT;
443 buffer = kmap(page);
444 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
445 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700446 if (err < 0)
447 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
450
451 flush_dcache_page(page);
452 SetPageUptodate(page);
453 if (PageError(page)) ClearPageError(page);
454 err = 0;
455 out:
456 kunmap(page);
457 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700458 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459}
460
Nick Pigginae361ff2007-10-16 01:25:17 -0700461int hostfs_write_begin(struct file *file, struct address_space *mapping,
462 loff_t pos, unsigned len, unsigned flags,
463 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464{
Nick Pigginae361ff2007-10-16 01:25:17 -0700465 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Nick Piggin54566b22009-01-04 12:00:53 -0800467 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700468 if (!*pagep)
469 return -ENOMEM;
470 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471}
472
Nick Pigginae361ff2007-10-16 01:25:17 -0700473int hostfs_write_end(struct file *file, struct address_space *mapping,
474 loff_t pos, unsigned len, unsigned copied,
475 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700478 void *buffer;
479 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
480 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700483 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700485
486 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
487 SetPageUptodate(page);
488
Jeff Dike84b3db02007-10-16 01:27:13 -0700489 /*
490 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700491 * i_size against the last byte written.
492 */
493 if (err > 0 && (pos > inode->i_size))
494 inode->i_size = pos;
495 unlock_page(page);
496 page_cache_release(page);
497
Jeff Dikef1adc052007-05-08 00:23:18 -0700498 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499}
500
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700501static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 .writepage = hostfs_writepage,
503 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700504 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700505 .write_begin = hostfs_write_begin,
506 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507};
508
Al Viro4754b822010-06-06 20:33:12 -0400509static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
Al Viro4754b822010-06-06 20:33:12 -0400511 dev_t rdev;
512 struct hostfs_stat st;
513 int err = stat_file(name, &st, -1);
514 if (err)
515 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Al Viro5e2df282010-06-06 19:38:18 -0400517 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400518 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Al Viro4754b822010-06-06 20:33:12 -0400520 switch (st.mode & S_IFMT) {
521 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400522 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400523 break;
524 case S_IFDIR:
525 ino->i_op = &hostfs_dir_iops;
526 ino->i_fop = &hostfs_dir_fops;
527 break;
528 case S_IFCHR:
529 case S_IFBLK:
530 case S_IFIFO:
531 case S_IFSOCK:
532 init_special_inode(ino, st.mode & S_IFMT, rdev);
533 ino->i_op = &hostfs_iops;
534 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Al Viro4754b822010-06-06 20:33:12 -0400536 default:
537 ino->i_op = &hostfs_iops;
538 ino->i_fop = &hostfs_file_fops;
539 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }
Al Viro4754b822010-06-06 20:33:12 -0400541
542 ino->i_ino = st.ino;
543 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200544 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800545 i_uid_write(ino, st.uid);
546 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400547 ino->i_atime = st.atime;
548 ino->i_mtime = st.mtime;
549 ino->i_ctime = st.ctime;
550 ino->i_size = st.size;
551 ino->i_blocks = st.blocks;
552 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553}
554
Al Viro4acdaf22011-07-26 01:42:34 -0400555int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400556 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557{
558 struct inode *inode;
559 char *name;
560 int error, fd;
561
David Howells0a370e52008-02-07 00:15:50 -0800562 inode = hostfs_iget(dir->i_sb);
563 if (IS_ERR(inode)) {
564 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700565 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400569 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700570 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 goto out_put;
572
573 fd = file_create(name,
574 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
575 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
576 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400577 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400579 else
Al Viro5e2df282010-06-06 19:38:18 -0400580 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Al Viroe9193052010-06-06 23:16:34 -0400582 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700583 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 goto out_put;
585
586 HOSTFS_I(inode)->fd = fd;
587 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
588 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700589 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
591 out_put:
592 iput(inode);
593 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700594 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595}
596
597struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Al Viro00cd8dd2012-06-10 17:13:09 -0400598 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
600 struct inode *inode;
601 char *name;
602 int err;
603
David Howells0a370e52008-02-07 00:15:50 -0800604 inode = hostfs_iget(ino->i_sb);
605 if (IS_ERR(inode)) {
606 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400611 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700612 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 goto out_put;
614
615 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400616
Al Viroe9193052010-06-06 23:16:34 -0400617 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700618 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 iput(inode);
620 inode = NULL;
621 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700622 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 goto out_put;
624
625 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700626 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628 out_put:
629 iput(inode);
630 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700631 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632}
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
635{
Jeff Dikef1adc052007-05-08 00:23:18 -0700636 char *from_name, *to_name;
637 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Al Viroc5322222010-06-06 20:42:10 -0400639 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700640 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400641 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700642 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400643 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700644 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700646 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400647 __putname(from_name);
648 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
651
652int hostfs_unlink(struct inode *ino, struct dentry *dentry)
653{
654 char *file;
655 int err;
656
Jeff Dike84b3db02007-10-16 01:27:13 -0700657 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700658 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Al Virof8d7e182010-06-06 23:19:04 -0400660 if ((file = dentry_name(dentry)) == NULL)
661 return -ENOMEM;
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400664 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700665 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666}
667
668int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
669{
670 char *file;
671 int err;
672
Al Viroc5322222010-06-06 20:42:10 -0400673 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700674 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400676 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700677 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678}
679
Al Viro18bb1db2011-07-26 01:41:39 -0400680int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
682 char *file;
683 int err;
684
Al Viroc5322222010-06-06 20:42:10 -0400685 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700686 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400688 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700689 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690}
691
692int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
693{
694 char *file;
695 int err;
696
Al Viroc5322222010-06-06 20:42:10 -0400697 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700698 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400700 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700701 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702}
703
Al Viro1a67aaf2011-07-26 01:52:52 -0400704static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
706 struct inode *inode;
707 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800708 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
David Howells0a370e52008-02-07 00:15:50 -0800710 inode = hostfs_iget(dir->i_sb);
711 if (IS_ERR(inode)) {
712 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400717 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700718 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 goto out_put;
720
721 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800722 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400723 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 goto out_free;
725
726 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400727 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400728 if (err)
729 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700730 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 goto out_put;
732
733 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700734 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400737 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 out_put:
739 iput(inode);
740 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700741 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
744int hostfs_rename(struct inode *from_ino, struct dentry *from,
745 struct inode *to_ino, struct dentry *to)
746{
747 char *from_name, *to_name;
748 int err;
749
Al Viroc5322222010-06-06 20:42:10 -0400750 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700751 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400752 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400753 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700754 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 }
756 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400757 __putname(from_name);
758 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700759 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760}
761
Al Viro10556cb2011-06-20 19:28:19 -0400762int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
764 char *name;
765 int r = 0, w = 0, x = 0, err;
766
Al Viro10556cb2011-06-20 19:28:19 -0400767 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100768 return -ECHILD;
769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (desired & MAY_READ) r = 1;
771 if (desired & MAY_WRITE) w = 1;
772 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400773 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700774 if (name == NULL)
775 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
777 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700778 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 err = 0;
780 else
781 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400782 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700783 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400784 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return err;
786}
787
788int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
789{
Christoph Hellwig10257742010-06-04 11:30:02 +0200790 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 struct hostfs_iattr attrs;
792 char *name;
793 int err;
794
Christoph Hellwig10257742010-06-04 11:30:02 +0200795 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700796
Christoph Hellwig10257742010-06-04 11:30:02 +0200797 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 if (err)
799 return err;
800
Jeff Dike84b3db02007-10-16 01:27:13 -0700801 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 attr->ia_valid &= ~ATTR_SIZE;
803
804 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700805 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 attrs.ia_valid |= HOSTFS_ATTR_MODE;
807 attrs.ia_mode = attr->ia_mode;
808 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700809 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800811 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700813 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800815 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700817 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
819 attrs.ia_size = attr->ia_size;
820 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700821 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
823 attrs.ia_atime = attr->ia_atime;
824 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700825 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
827 attrs.ia_mtime = attr->ia_mtime;
828 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700829 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
831 attrs.ia_ctime = attr->ia_ctime;
832 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700833 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
835 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700836 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
838 }
Al Viroc5322222010-06-06 20:42:10 -0400839 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700840 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700841 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700842 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400843 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700844 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700845 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Christoph Hellwig10257742010-06-04 11:30:02 +0200847 if ((attr->ia_valid & ATTR_SIZE) &&
848 attr->ia_size != i_size_read(inode)) {
849 int error;
850
Marco Stornelli3be2be02012-10-06 10:31:13 +0200851 error = inode_newsize_ok(inode, attr->ia_size);
852 if (error)
853 return error;
854
855 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200856 }
857
858 setattr_copy(inode, attr);
859 mark_inode_dirty(inode);
860 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861}
862
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800863static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 .create = hostfs_create,
865 .link = hostfs_link,
866 .unlink = hostfs_unlink,
867 .symlink = hostfs_symlink,
868 .mkdir = hostfs_mkdir,
869 .rmdir = hostfs_rmdir,
870 .mknod = hostfs_mknod,
871 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 .permission = hostfs_permission,
873 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874};
875
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800876static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 .create = hostfs_create,
878 .lookup = hostfs_lookup,
879 .link = hostfs_link,
880 .unlink = hostfs_unlink,
881 .symlink = hostfs_symlink,
882 .mkdir = hostfs_mkdir,
883 .rmdir = hostfs_rmdir,
884 .mknod = hostfs_mknod,
885 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 .permission = hostfs_permission,
887 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888};
889
Al Virod0352d32010-06-06 21:51:16 -0400890static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891{
Al Virod0352d32010-06-06 21:51:16 -0400892 char *link = __getname();
893 if (link) {
894 char *path = dentry_name(dentry);
895 int err = -ENOMEM;
896 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400897 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400898 if (err == PATH_MAX)
899 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400900 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400901 }
902 if (err < 0) {
903 __putname(link);
904 link = ERR_PTR(err);
905 }
906 } else {
907 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 }
Al Virod0352d32010-06-06 21:51:16 -0400909
910 nd_set_link(nd, link);
911 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912}
913
Al Virod0352d32010-06-06 21:51:16 -0400914static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
915{
916 char *s = nd_get_link(nd);
917 if (!IS_ERR(s))
918 __putname(s);
919}
920
921static const struct inode_operations hostfs_link_iops = {
922 .readlink = generic_readlink,
923 .follow_link = hostfs_follow_link,
924 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925};
926
927static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
928{
929 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700930 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 int err;
932
933 sb->s_blocksize = 1024;
934 sb->s_blocksize_bits = 10;
935 sb->s_magic = HOSTFS_SUPER_MAGIC;
936 sb->s_op = &hostfs_sbops;
Al Virof772c4a2011-01-12 16:47:00 -0500937 sb->s_d_op = &hostfs_dentry_ops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700938 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800940 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700941 if (req_root == NULL)
942 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400945 sb->s_fs_info = host_root_path =
946 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700947 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 goto out;
949
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700950 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Al Viro52b209f2010-06-06 18:43:19 -0400952 root_inode = new_inode(sb);
953 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400954 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Al Viro4754b822010-06-06 20:33:12 -0400956 err = read_name(root_inode, host_root_path);
957 if (err)
958 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400959
Al Viro4754b822010-06-06 20:33:12 -0400960 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400961 char *name = follow_link(host_root_path);
962 if (IS_ERR(name))
963 err = PTR_ERR(name);
964 else
965 err = read_name(root_inode, name);
966 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400967 if (err)
968 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500972 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700973 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500974 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
Jeff Dikef1adc052007-05-08 00:23:18 -0700976 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Jeff Dikef1adc052007-05-08 00:23:18 -0700978out_put:
979 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700980out:
981 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982}
983
Al Viro3c26ff62010-07-25 11:46:36 +0400984static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700985 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400986 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
Al Viro3c26ff62010-07-25 11:46:36 +0400988 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989}
990
Al Viro601d2c32010-06-06 17:53:01 -0400991static void hostfs_kill_sb(struct super_block *s)
992{
993 kill_anon_super(s);
994 kfree(s->s_fs_info);
995}
996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997static struct file_system_type hostfs_type = {
998 .owner = THIS_MODULE,
999 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001000 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -04001001 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 .fs_flags = 0,
1003};
1004
1005static int __init init_hostfs(void)
1006{
Jeff Dikef1adc052007-05-08 00:23:18 -07001007 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008}
1009
1010static void __exit exit_hostfs(void)
1011{
1012 unregister_filesystem(&hostfs_type);
1013}
1014
1015module_init(init_hostfs)
1016module_exit(exit_hostfs)
1017MODULE_LICENSE("GPL");