blob: 9c470fde9878eae280eeb62b7ef9ca3c263c9b4c [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,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700381 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200382 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 .aio_read = generic_file_aio_read,
384 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700385 .write = do_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
James Hogan9e443bc2013-11-14 21:15:13 +0000744static int hostfs_rename(struct inode *from_ino, struct dentry *from,
745 struct inode *to_ino, struct dentry *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
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
James Hogan9e443bc2013-11-14 21:15:13 +0000762static int 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
James Hogan9e443bc2013-11-14 21:15:13 +0000788static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
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) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200848 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200849 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200850
851 setattr_copy(inode, attr);
852 mark_inode_dirty(inode);
853 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854}
855
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800856static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 .permission = hostfs_permission,
858 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859};
860
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800861static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 .create = hostfs_create,
863 .lookup = hostfs_lookup,
864 .link = hostfs_link,
865 .unlink = hostfs_unlink,
866 .symlink = hostfs_symlink,
867 .mkdir = hostfs_mkdir,
868 .rmdir = hostfs_rmdir,
869 .mknod = hostfs_mknod,
870 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 .permission = hostfs_permission,
872 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873};
874
Al Virod0352d32010-06-06 21:51:16 -0400875static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
Al Virod0352d32010-06-06 21:51:16 -0400877 char *link = __getname();
878 if (link) {
879 char *path = dentry_name(dentry);
880 int err = -ENOMEM;
881 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400882 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400883 if (err == PATH_MAX)
884 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400885 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400886 }
887 if (err < 0) {
888 __putname(link);
889 link = ERR_PTR(err);
890 }
891 } else {
892 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 }
Al Virod0352d32010-06-06 21:51:16 -0400894
895 nd_set_link(nd, link);
896 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897}
898
Al Virod0352d32010-06-06 21:51:16 -0400899static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
900{
901 char *s = nd_get_link(nd);
902 if (!IS_ERR(s))
903 __putname(s);
904}
905
906static const struct inode_operations hostfs_link_iops = {
907 .readlink = generic_readlink,
908 .follow_link = hostfs_follow_link,
909 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910};
911
912static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
913{
914 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700915 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 int err;
917
918 sb->s_blocksize = 1024;
919 sb->s_blocksize_bits = 10;
920 sb->s_magic = HOSTFS_SUPER_MAGIC;
921 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400922 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700923 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800925 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700926 if (req_root == NULL)
927 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
929 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400930 sb->s_fs_info = host_root_path =
931 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700932 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 goto out;
934
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700935 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Al Viro52b209f72010-06-06 18:43:19 -0400937 root_inode = new_inode(sb);
938 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400939 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Al Viro4754b822010-06-06 20:33:12 -0400941 err = read_name(root_inode, host_root_path);
942 if (err)
943 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400944
Al Viro4754b822010-06-06 20:33:12 -0400945 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400946 char *name = follow_link(host_root_path);
947 if (IS_ERR(name))
948 err = PTR_ERR(name);
949 else
950 err = read_name(root_inode, name);
951 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400952 if (err)
953 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500957 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700958 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500959 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Jeff Dikef1adc052007-05-08 00:23:18 -0700961 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Jeff Dikef1adc052007-05-08 00:23:18 -0700963out_put:
964 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700965out:
966 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967}
968
Al Viro3c26ff62010-07-25 11:46:36 +0400969static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700970 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400971 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
Al Viro3c26ff62010-07-25 11:46:36 +0400973 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
Al Viro601d2c32010-06-06 17:53:01 -0400976static void hostfs_kill_sb(struct super_block *s)
977{
978 kill_anon_super(s);
979 kfree(s->s_fs_info);
980}
981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982static struct file_system_type hostfs_type = {
983 .owner = THIS_MODULE,
984 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400985 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400986 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 .fs_flags = 0,
988};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700989MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991static int __init init_hostfs(void)
992{
Jeff Dikef1adc052007-05-08 00:23:18 -0700993 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994}
995
996static void __exit exit_hostfs(void)
997{
998 unregister_filesystem(&hostfs_type);
999}
1000
1001module_init(init_hostfs)
1002module_exit(exit_hostfs)
1003MODULE_LICENSE("GPL");