blob: fd62cae0fdcb66db03712d419c25014312112546 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070036/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080037static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070038static int append = 0;
39
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080040static const struct inode_operations hostfs_iops;
41static const struct inode_operations hostfs_dir_iops;
Al Virod0352d32010-06-06 21:51:16 -040042static const struct inode_operations hostfs_link_iops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44#ifndef MODULE
45static int __init hostfs_args(char *options, int *add)
46{
47 char *ptr;
48
49 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070050 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070052 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 root_ino = options;
54
55 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070056 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070058 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070060 if (*options != '\0') {
61 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 append = 1;
63 else printf("hostfs_args - unsupported option - %s\n",
64 options);
65 }
66 options = ptr;
67 }
Jeff Dikef1adc052007-05-08 00:23:18 -070068 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
70
71__uml_setup("hostfs=", hostfs_args,
72"hostfs=<root dir>,<flags>,...\n"
73" This is used to set hostfs parameters. The root directory argument\n"
74" is used to confine all hostfs mounts to within the specified directory\n"
75" tree on the host. If this isn't specified, then a user inside UML can\n"
76" mount anything on the host that's accessible to the user that's running\n"
77" it.\n"
78" The only flag currently supported is 'append', which specifies that all\n"
79" files opened by hostfs will be opened in append mode.\n\n"
80);
81#endif
82
Al Viroe9193052010-06-06 23:16:34 -040083static char *__dentry_name(struct dentry *dentry, char *name)
84{
Nick Pigginec2447c2011-01-07 17:49:29 +110085 char *p = dentry_path_raw(dentry, name, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040086 char *root;
87 size_t len;
88
Al Viroe9193052010-06-06 23:16:34 -040089 root = dentry->d_sb->s_fs_info;
90 len = strlen(root);
91 if (IS_ERR(p)) {
92 __putname(name);
93 return NULL;
94 }
Al Viro850a4962010-08-18 06:18:57 -040095 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040096 if (len > p - name) {
97 __putname(name);
98 return NULL;
99 }
100 if (p > name + len) {
101 char *s = name + len;
102 while ((*s++ = *p++) != '\0')
103 ;
104 }
105 return name;
106}
107
Al Viroc5322222010-06-06 20:42:10 -0400108static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
Al Viroe9193052010-06-06 23:16:34 -0400110 char *name = __getname();
111 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700112 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
James Hogan9dcc5e82013-03-27 10:47:12 +0000114 return __dentry_name(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115}
116
Al Viroc5322222010-06-06 20:42:10 -0400117static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118{
119 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100120 char *name;
121
122 dentry = d_find_alias(ino);
123 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400124 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Nick Pigginec2447c2011-01-07 17:49:29 +1100126 name = dentry_name(dentry);
127
128 dput(dentry);
129
130 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133static char *follow_link(char *link)
134{
135 int len, n;
136 char *name, *resolved, *end;
137
138 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700139 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 n = -ENOMEM;
141 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700142 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 goto out;
144
WANG Congea7e7432008-11-19 15:36:46 -0800145 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700146 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 break;
148 len *= 2;
149 kfree(name);
150 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700151 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 goto out_free;
153
Jeff Dike84b3db02007-10-16 01:27:13 -0700154 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700155 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700158 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700159 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161 *(end + 1) = '\0';
162 len = strlen(link) + strlen(name) + 1;
163
164 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700165 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 n = -ENOMEM;
167 goto out_free;
168 }
169
170 sprintf(resolved, "%s%s", link, name);
171 kfree(name);
172 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700173 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175 out_free:
176 kfree(name);
177 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700178 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
David Howells0a370e52008-02-07 00:15:50 -0800181static struct inode *hostfs_iget(struct super_block *sb)
182{
Al Viro52b209f72010-06-06 18:43:19 -0400183 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800184 if (!inode)
185 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800186 return inode;
187}
188
James Hogan9e443bc2013-11-14 21:15:13 +0000189static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
Jeff Dike84b3db02007-10-16 01:27:13 -0700191 /*
192 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 * struct statfs still has 32-bit versions for most of these fields,
194 * so we convert them here
195 */
196 int err;
197 long long f_blocks;
198 long long f_bfree;
199 long long f_bavail;
200 long long f_files;
201 long long f_ffree;
202
Al Viro601d2c32010-06-06 17:53:01 -0400203 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
205 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700206 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700207 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700208 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 sf->f_blocks = f_blocks;
210 sf->f_bfree = f_bfree;
211 sf->f_bavail = f_bavail;
212 sf->f_files = f_files;
213 sf->f_ffree = f_ffree;
214 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700215 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
218static struct inode *hostfs_alloc_inode(struct super_block *sb)
219{
220 struct hostfs_inode_info *hi;
221
James Hogan371fdab2013-03-27 10:47:14 +0000222 hi = kmalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700223 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700224 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400225 hi->fd = -1;
James Hogan371fdab2013-03-27 10:47:14 +0000226 hi->mode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700228 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229}
230
Al Viroe971a6d2010-06-06 15:16:17 -0400231static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
Johannes Weiner91b0abe2014-04-03 14:47:49 -0700233 truncate_inode_pages_final(&inode->i_data);
Jan Karadbd57682012-05-03 14:48:02 +0200234 clear_inode(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700235 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 close_file(&HOSTFS_I(inode)->fd);
237 HOSTFS_I(inode)->fd = -1;
238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239}
240
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100241static void hostfs_i_callback(struct rcu_head *head)
242{
243 struct inode *inode = container_of(head, struct inode, i_rcu);
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100244 kfree(HOSTFS_I(inode));
245}
246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247static void hostfs_destroy_inode(struct inode *inode)
248{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100249 call_rcu(&inode->i_rcu, hostfs_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250}
251
Al Viro34c80b12011-12-08 21:32:45 -0500252static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800253{
Al Viro34c80b12011-12-08 21:32:45 -0500254 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800255 size_t offset = strlen(root_ino) + 1;
256
257 if (strlen(root_path) > offset)
258 seq_printf(seq, ",%s", root_path + offset);
259
260 return 0;
261}
262
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800263static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400266 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800268 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269};
270
James Hogan9e443bc2013-11-14 21:15:13 +0000271static int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{
273 void *dir;
274 char *name;
275 unsigned long long next, ino;
276 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100277 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Al Viroc5322222010-06-06 20:42:10 -0400279 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700280 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700281 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400283 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700284 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700285 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400286 next = ctx->pos;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100287 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400288 if (!dir_emit(ctx, name, len, ino, type))
289 break;
290 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 }
292 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700293 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
James Hogan9e443bc2013-11-14 21:15:13 +0000296static int hostfs_file_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297{
Al Virof8ad8502010-06-06 23:49:18 -0400298 static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400300 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400301 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400302 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700305 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700306 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Al Virof8ad8502010-06-06 23:49:18 -0400308 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Al Virof8ad8502010-06-06 23:49:18 -0400310retry:
311 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400313 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700315 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 r = 1;
317
Al Viroc5322222010-06-06 20:42:10 -0400318 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700319 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700320 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400323 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700324 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700325 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400326
327 mutex_lock(&open_mutex);
328 /* somebody else had handled it first? */
329 if ((mode & HOSTFS_I(ino)->mode) == mode) {
330 mutex_unlock(&open_mutex);
331 return 0;
332 }
333 if ((mode | HOSTFS_I(ino)->mode) != mode) {
334 mode |= HOSTFS_I(ino)->mode;
335 mutex_unlock(&open_mutex);
336 close_file(&fd);
337 goto retry;
338 }
339 if (HOSTFS_I(ino)->fd == -1) {
340 HOSTFS_I(ino)->fd = fd;
341 } else {
342 err = replace_file(fd, HOSTFS_I(ino)->fd);
343 close_file(&fd);
344 if (err < 0) {
345 mutex_unlock(&open_mutex);
346 return err;
347 }
348 }
349 HOSTFS_I(ino)->mode = mode;
350 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Jeff Dikef1adc052007-05-08 00:23:18 -0700352 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353}
354
Richard Weinberger65984ff2013-08-04 17:23:51 +0000355static int hostfs_file_release(struct inode *inode, struct file *file)
356{
357 filemap_write_and_wait(inode->i_mapping);
358
359 return 0;
360}
361
James Hogan9e443bc2013-11-14 21:15:13 +0000362static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
363 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
Josef Bacik02c24a82011-07-16 20:44:56 -0400365 struct inode *inode = file->f_mapping->host;
366 int ret;
367
368 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
369 if (ret)
370 return ret;
371
372 mutex_lock(&inode->i_mutex);
373 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
374 mutex_unlock(&inode->i_mutex);
375
376 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
378
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800379static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 .llseek = generic_file_llseek,
Al Viroaad4f8b2014-04-02 14:33:16 -0400381 .read = new_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200382 .splice_read = generic_file_splice_read,
Al Viroaad4f8b2014-04-02 14:33:16 -0400383 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400384 .write_iter = generic_file_write_iter,
385 .write = new_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 .mmap = generic_file_mmap,
387 .open = hostfs_file_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000388 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 .fsync = hostfs_fsync,
390};
391
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800392static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 .llseek = generic_file_llseek,
Al Viro8e28bc72013-05-22 16:34:19 -0400394 .iterate = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 .read = generic_read_dir,
396};
397
James Hogan9e443bc2013-11-14 21:15:13 +0000398static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
400 struct address_space *mapping = page->mapping;
401 struct inode *inode = mapping->host;
402 char *buffer;
403 unsigned long long base;
404 int count = PAGE_CACHE_SIZE;
405 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
406 int err;
407
408 if (page->index >= end_index)
409 count = inode->i_size & (PAGE_CACHE_SIZE-1);
410
411 buffer = kmap(page);
412 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
413
414 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700415 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 ClearPageUptodate(page);
417 goto out;
418 }
419
420 if (base > inode->i_size)
421 inode->i_size = base;
422
423 if (PageError(page))
424 ClearPageError(page);
425 err = 0;
426
427 out:
428 kunmap(page);
429
430 unlock_page(page);
431 return err;
432}
433
James Hogan9e443bc2013-11-14 21:15:13 +0000434static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
436 char *buffer;
437 long long start;
438 int err = 0;
439
440 start = (long long) page->index << PAGE_CACHE_SHIFT;
441 buffer = kmap(page);
442 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
443 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700444 if (err < 0)
445 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
448
449 flush_dcache_page(page);
450 SetPageUptodate(page);
451 if (PageError(page)) ClearPageError(page);
452 err = 0;
453 out:
454 kunmap(page);
455 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700456 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458
James Hogan9e443bc2013-11-14 21:15:13 +0000459static int hostfs_write_begin(struct file *file, struct address_space *mapping,
460 loff_t pos, unsigned len, unsigned flags,
461 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Nick Pigginae361ff2007-10-16 01:25:17 -0700463 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Nick Piggin54566b22009-01-04 12:00:53 -0800465 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700466 if (!*pagep)
467 return -ENOMEM;
468 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469}
470
James Hogan9e443bc2013-11-14 21:15:13 +0000471static int hostfs_write_end(struct file *file, struct address_space *mapping,
472 loff_t pos, unsigned len, unsigned copied,
473 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700476 void *buffer;
477 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
478 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700481 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700483
484 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
485 SetPageUptodate(page);
486
Jeff Dike84b3db02007-10-16 01:27:13 -0700487 /*
488 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700489 * i_size against the last byte written.
490 */
491 if (err > 0 && (pos > inode->i_size))
492 inode->i_size = pos;
493 unlock_page(page);
494 page_cache_release(page);
495
Jeff Dikef1adc052007-05-08 00:23:18 -0700496 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700499static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 .writepage = hostfs_writepage,
501 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700502 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700503 .write_begin = hostfs_write_begin,
504 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505};
506
Al Viro4754b822010-06-06 20:33:12 -0400507static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
Al Viro4754b822010-06-06 20:33:12 -0400509 dev_t rdev;
510 struct hostfs_stat st;
511 int err = stat_file(name, &st, -1);
512 if (err)
513 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Al Viro5e2df282010-06-06 19:38:18 -0400515 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400516 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Al Viro4754b822010-06-06 20:33:12 -0400518 switch (st.mode & S_IFMT) {
519 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400520 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400521 break;
522 case S_IFDIR:
523 ino->i_op = &hostfs_dir_iops;
524 ino->i_fop = &hostfs_dir_fops;
525 break;
526 case S_IFCHR:
527 case S_IFBLK:
528 case S_IFIFO:
529 case S_IFSOCK:
530 init_special_inode(ino, st.mode & S_IFMT, rdev);
531 ino->i_op = &hostfs_iops;
532 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
Al Viro4754b822010-06-06 20:33:12 -0400534 default:
535 ino->i_op = &hostfs_iops;
536 ino->i_fop = &hostfs_file_fops;
537 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 }
Al Viro4754b822010-06-06 20:33:12 -0400539
540 ino->i_ino = st.ino;
541 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200542 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800543 i_uid_write(ino, st.uid);
544 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400545 ino->i_atime = st.atime;
546 ino->i_mtime = st.mtime;
547 ino->i_ctime = st.ctime;
548 ino->i_size = st.size;
549 ino->i_blocks = st.blocks;
550 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551}
552
James Hogan9e443bc2013-11-14 21:15:13 +0000553static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
554 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
556 struct inode *inode;
557 char *name;
558 int error, fd;
559
David Howells0a370e52008-02-07 00:15:50 -0800560 inode = hostfs_iget(dir->i_sb);
561 if (IS_ERR(inode)) {
562 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700563 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400567 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700568 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 goto out_put;
570
571 fd = file_create(name,
572 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
573 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
574 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400575 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400577 else
Al Viro5e2df282010-06-06 19:38:18 -0400578 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Al Viroe9193052010-06-06 23:16:34 -0400580 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700581 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 goto out_put;
583
584 HOSTFS_I(inode)->fd = fd;
585 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
586 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700587 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589 out_put:
590 iput(inode);
591 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700592 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593}
594
James Hogan9e443bc2013-11-14 21:15:13 +0000595static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
596 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
598 struct inode *inode;
599 char *name;
600 int err;
601
David Howells0a370e52008-02-07 00:15:50 -0800602 inode = hostfs_iget(ino->i_sb);
603 if (IS_ERR(inode)) {
604 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400609 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700610 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 goto out_put;
612
613 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400614
Al Viroe9193052010-06-06 23:16:34 -0400615 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700616 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 iput(inode);
618 inode = NULL;
619 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700620 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 goto out_put;
622
623 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700624 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 out_put:
627 iput(inode);
628 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700629 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630}
631
James Hogan9e443bc2013-11-14 21:15:13 +0000632static int hostfs_link(struct dentry *to, struct inode *ino,
633 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
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
James Hogan9e443bc2013-11-14 21:15:13 +0000651static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
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
James Hogan9e443bc2013-11-14 21:15:13 +0000667static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
668 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669{
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
James Hogan9e443bc2013-11-14 21:15:13 +0000680static int 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
James Hogan9e443bc2013-11-14 21:15:13 +0000692static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
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
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200744static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
745 struct inode *new_dir, struct dentry *new_dentry,
746 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200748 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 int err;
750
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200751 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
752 return -EINVAL;
753
754 old_name = dentry_name(old_dentry);
755 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700756 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200757 new_name = dentry_name(new_dentry);
758 if (new_name == NULL) {
759 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700760 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200762 if (!flags)
763 err = rename_file(old_name, new_name);
764 else
765 err = rename2_file(old_name, new_name, flags);
766
767 __putname(old_name);
768 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700769 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770}
771
James Hogan9e443bc2013-11-14 21:15:13 +0000772static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
774 char *name;
775 int r = 0, w = 0, x = 0, err;
776
Al Viro10556cb2011-06-20 19:28:19 -0400777 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100778 return -ECHILD;
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 if (desired & MAY_READ) r = 1;
781 if (desired & MAY_WRITE) w = 1;
782 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400783 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700784 if (name == NULL)
785 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700788 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 err = 0;
790 else
791 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400792 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700793 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400794 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 return err;
796}
797
James Hogan9e443bc2013-11-14 21:15:13 +0000798static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799{
Christoph Hellwig10257742010-06-04 11:30:02 +0200800 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 struct hostfs_iattr attrs;
802 char *name;
803 int err;
804
Christoph Hellwig10257742010-06-04 11:30:02 +0200805 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700806
Christoph Hellwig10257742010-06-04 11:30:02 +0200807 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 if (err)
809 return err;
810
Jeff Dike84b3db02007-10-16 01:27:13 -0700811 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 attr->ia_valid &= ~ATTR_SIZE;
813
814 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700815 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 attrs.ia_valid |= HOSTFS_ATTR_MODE;
817 attrs.ia_mode = attr->ia_mode;
818 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700819 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800821 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700823 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800825 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700827 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
829 attrs.ia_size = attr->ia_size;
830 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700831 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
833 attrs.ia_atime = attr->ia_atime;
834 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700835 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
837 attrs.ia_mtime = attr->ia_mtime;
838 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
841 attrs.ia_ctime = attr->ia_ctime;
842 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700843 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
845 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700846 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
848 }
Al Viroc5322222010-06-06 20:42:10 -0400849 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700850 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700851 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700852 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400853 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700854 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700855 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Christoph Hellwig10257742010-06-04 11:30:02 +0200857 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200858 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200859 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200860
861 setattr_copy(inode, attr);
862 mark_inode_dirty(inode);
863 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864}
865
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800866static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 .permission = hostfs_permission,
868 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869};
870
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800871static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 .create = hostfs_create,
873 .lookup = hostfs_lookup,
874 .link = hostfs_link,
875 .unlink = hostfs_unlink,
876 .symlink = hostfs_symlink,
877 .mkdir = hostfs_mkdir,
878 .rmdir = hostfs_rmdir,
879 .mknod = hostfs_mknod,
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200880 .rename2 = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 .permission = hostfs_permission,
882 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883};
884
Al Virod0352d32010-06-06 21:51:16 -0400885static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
Al Virod0352d32010-06-06 21:51:16 -0400887 char *link = __getname();
888 if (link) {
889 char *path = dentry_name(dentry);
890 int err = -ENOMEM;
891 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400892 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400893 if (err == PATH_MAX)
894 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400895 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400896 }
897 if (err < 0) {
898 __putname(link);
899 link = ERR_PTR(err);
900 }
901 } else {
902 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 }
Al Virod0352d32010-06-06 21:51:16 -0400904
905 nd_set_link(nd, link);
906 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907}
908
Al Virod0352d32010-06-06 21:51:16 -0400909static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
910{
911 char *s = nd_get_link(nd);
912 if (!IS_ERR(s))
913 __putname(s);
914}
915
916static const struct inode_operations hostfs_link_iops = {
917 .readlink = generic_readlink,
918 .follow_link = hostfs_follow_link,
919 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920};
921
922static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
923{
924 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700925 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 int err;
927
928 sb->s_blocksize = 1024;
929 sb->s_blocksize_bits = 10;
930 sb->s_magic = HOSTFS_SUPER_MAGIC;
931 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400932 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700933 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800935 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700936 if (req_root == NULL)
937 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
939 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400940 sb->s_fs_info = host_root_path =
941 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700942 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 goto out;
944
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700945 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
Al Viro52b209f72010-06-06 18:43:19 -0400947 root_inode = new_inode(sb);
948 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400949 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Al Viro4754b822010-06-06 20:33:12 -0400951 err = read_name(root_inode, host_root_path);
952 if (err)
953 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400954
Al Viro4754b822010-06-06 20:33:12 -0400955 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400956 char *name = follow_link(host_root_path);
957 if (IS_ERR(name))
958 err = PTR_ERR(name);
959 else
960 err = read_name(root_inode, name);
961 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400962 if (err)
963 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500967 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700968 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500969 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Jeff Dikef1adc052007-05-08 00:23:18 -0700971 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Jeff Dikef1adc052007-05-08 00:23:18 -0700973out_put:
974 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700975out:
976 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977}
978
Al Viro3c26ff62010-07-25 11:46:36 +0400979static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700980 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400981 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
Al Viro3c26ff62010-07-25 11:46:36 +0400983 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984}
985
Al Viro601d2c32010-06-06 17:53:01 -0400986static void hostfs_kill_sb(struct super_block *s)
987{
988 kill_anon_super(s);
989 kfree(s->s_fs_info);
990}
991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992static struct file_system_type hostfs_type = {
993 .owner = THIS_MODULE,
994 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400995 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400996 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 .fs_flags = 0,
998};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700999MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
1001static int __init init_hostfs(void)
1002{
Jeff Dikef1adc052007-05-08 00:23:18 -07001003 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004}
1005
1006static void __exit exit_hostfs(void)
1007{
1008 unregister_filesystem(&hostfs_type);
1009}
1010
1011module_init(init_hostfs)
1012module_exit(exit_hostfs)
1013MODULE_LICENSE("GPL");