blob: db23ce1bd9031028390eb33016a05783950bc379 [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
David Howells726c3342006-06-23 02:02:58 -0700189int 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{
Mark Fashehfef26652005-09-09 13:01:31 -0700233 truncate_inode_pages(&inode->i_data, 0);
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
Al Viro8e28bc72013-05-22 16:34:19 -0400271int 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
296int hostfs_file_open(struct inode *ino, struct file *file)
297{
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
Josef Bacik02c24a82011-07-16 20:44:56 -0400362int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Josef Bacik02c24a82011-07-16 20:44:56 -0400364 struct inode *inode = file->f_mapping->host;
365 int ret;
366
367 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
368 if (ret)
369 return ret;
370
371 mutex_lock(&inode->i_mutex);
372 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
373 mutex_unlock(&inode->i_mutex);
374
375 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376}
377
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800378static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700380 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200381 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 .aio_read = generic_file_aio_read,
383 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700384 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 .mmap = generic_file_mmap,
386 .open = hostfs_file_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000387 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 .fsync = hostfs_fsync,
389};
390
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800391static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 .llseek = generic_file_llseek,
Al Viro8e28bc72013-05-22 16:34:19 -0400393 .iterate = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 .read = generic_read_dir,
395};
396
397int hostfs_writepage(struct page *page, struct writeback_control *wbc)
398{
399 struct address_space *mapping = page->mapping;
400 struct inode *inode = mapping->host;
401 char *buffer;
402 unsigned long long base;
403 int count = PAGE_CACHE_SIZE;
404 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
405 int err;
406
407 if (page->index >= end_index)
408 count = inode->i_size & (PAGE_CACHE_SIZE-1);
409
410 buffer = kmap(page);
411 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
412
413 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700414 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 ClearPageUptodate(page);
416 goto out;
417 }
418
419 if (base > inode->i_size)
420 inode->i_size = base;
421
422 if (PageError(page))
423 ClearPageError(page);
424 err = 0;
425
426 out:
427 kunmap(page);
428
429 unlock_page(page);
430 return err;
431}
432
433int hostfs_readpage(struct file *file, struct page *page)
434{
435 char *buffer;
436 long long start;
437 int err = 0;
438
439 start = (long long) page->index << PAGE_CACHE_SHIFT;
440 buffer = kmap(page);
441 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
442 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700443 if (err < 0)
444 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
447
448 flush_dcache_page(page);
449 SetPageUptodate(page);
450 if (PageError(page)) ClearPageError(page);
451 err = 0;
452 out:
453 kunmap(page);
454 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700455 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456}
457
Nick Pigginae361ff2007-10-16 01:25:17 -0700458int hostfs_write_begin(struct file *file, struct address_space *mapping,
459 loff_t pos, unsigned len, unsigned flags,
460 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
Nick Pigginae361ff2007-10-16 01:25:17 -0700462 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
Nick Piggin54566b22009-01-04 12:00:53 -0800464 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700465 if (!*pagep)
466 return -ENOMEM;
467 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
Nick Pigginae361ff2007-10-16 01:25:17 -0700470int hostfs_write_end(struct file *file, struct address_space *mapping,
471 loff_t pos, unsigned len, unsigned copied,
472 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700475 void *buffer;
476 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
477 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700480 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700482
483 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
484 SetPageUptodate(page);
485
Jeff Dike84b3db02007-10-16 01:27:13 -0700486 /*
487 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700488 * i_size against the last byte written.
489 */
490 if (err > 0 && (pos > inode->i_size))
491 inode->i_size = pos;
492 unlock_page(page);
493 page_cache_release(page);
494
Jeff Dikef1adc052007-05-08 00:23:18 -0700495 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496}
497
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700498static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 .writepage = hostfs_writepage,
500 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700501 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700502 .write_begin = hostfs_write_begin,
503 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504};
505
Al Viro4754b822010-06-06 20:33:12 -0400506static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
Al Viro4754b822010-06-06 20:33:12 -0400508 dev_t rdev;
509 struct hostfs_stat st;
510 int err = stat_file(name, &st, -1);
511 if (err)
512 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Al Viro5e2df282010-06-06 19:38:18 -0400514 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400515 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Al Viro4754b822010-06-06 20:33:12 -0400517 switch (st.mode & S_IFMT) {
518 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400519 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400520 break;
521 case S_IFDIR:
522 ino->i_op = &hostfs_dir_iops;
523 ino->i_fop = &hostfs_dir_fops;
524 break;
525 case S_IFCHR:
526 case S_IFBLK:
527 case S_IFIFO:
528 case S_IFSOCK:
529 init_special_inode(ino, st.mode & S_IFMT, rdev);
530 ino->i_op = &hostfs_iops;
531 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
Al Viro4754b822010-06-06 20:33:12 -0400533 default:
534 ino->i_op = &hostfs_iops;
535 ino->i_fop = &hostfs_file_fops;
536 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 }
Al Viro4754b822010-06-06 20:33:12 -0400538
539 ino->i_ino = st.ino;
540 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200541 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800542 i_uid_write(ino, st.uid);
543 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400544 ino->i_atime = st.atime;
545 ino->i_mtime = st.mtime;
546 ino->i_ctime = st.ctime;
547 ino->i_size = st.size;
548 ino->i_blocks = st.blocks;
549 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550}
551
Al Viro4acdaf22011-07-26 01:42:34 -0400552int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400553 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
555 struct inode *inode;
556 char *name;
557 int error, fd;
558
David Howells0a370e52008-02-07 00:15:50 -0800559 inode = hostfs_iget(dir->i_sb);
560 if (IS_ERR(inode)) {
561 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700562 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400566 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700567 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 goto out_put;
569
570 fd = file_create(name,
571 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
572 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
573 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400574 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400576 else
Al Viro5e2df282010-06-06 19:38:18 -0400577 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Al Viroe9193052010-06-06 23:16:34 -0400579 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700580 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 goto out_put;
582
583 HOSTFS_I(inode)->fd = fd;
584 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
585 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700586 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 out_put:
589 iput(inode);
590 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700591 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592}
593
594struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Al Viro00cd8dd2012-06-10 17:13:09 -0400595 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
597 struct inode *inode;
598 char *name;
599 int err;
600
David Howells0a370e52008-02-07 00:15:50 -0800601 inode = hostfs_iget(ino->i_sb);
602 if (IS_ERR(inode)) {
603 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400608 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700609 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 goto out_put;
611
612 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400613
Al Viroe9193052010-06-06 23:16:34 -0400614 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700615 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 iput(inode);
617 inode = NULL;
618 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700619 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 goto out_put;
621
622 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700623 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625 out_put:
626 iput(inode);
627 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700628 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629}
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
632{
Jeff Dikef1adc052007-05-08 00:23:18 -0700633 char *from_name, *to_name;
634 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Al Viroc5322222010-06-06 20:42:10 -0400636 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700637 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400638 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700639 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400640 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700641 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700643 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400644 __putname(from_name);
645 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700646 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
649int hostfs_unlink(struct inode *ino, struct dentry *dentry)
650{
651 char *file;
652 int err;
653
Jeff Dike84b3db02007-10-16 01:27:13 -0700654 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Al Virof8d7e182010-06-06 23:19:04 -0400657 if ((file = dentry_name(dentry)) == NULL)
658 return -ENOMEM;
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400661 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700662 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663}
664
665int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
666{
667 char *file;
668 int err;
669
Al Viroc5322222010-06-06 20:42:10 -0400670 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700671 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400673 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700674 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675}
676
Al Viro18bb1db2011-07-26 01:41:39 -0400677int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678{
679 char *file;
680 int err;
681
Al Viroc5322222010-06-06 20:42:10 -0400682 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700683 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400685 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700686 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
688
689int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
690{
691 char *file;
692 int err;
693
Al Viroc5322222010-06-06 20:42:10 -0400694 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700695 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400697 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700698 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699}
700
Al Viro1a67aaf2011-07-26 01:52:52 -0400701static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
703 struct inode *inode;
704 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800705 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
David Howells0a370e52008-02-07 00:15:50 -0800707 inode = hostfs_iget(dir->i_sb);
708 if (IS_ERR(inode)) {
709 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800711 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400714 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700715 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 goto out_put;
717
718 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800719 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400720 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 goto out_free;
722
723 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400724 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400725 if (err)
726 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700727 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 goto out_put;
729
730 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700731 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400734 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 out_put:
736 iput(inode);
737 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700738 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739}
740
741int hostfs_rename(struct inode *from_ino, struct dentry *from,
742 struct inode *to_ino, struct dentry *to)
743{
744 char *from_name, *to_name;
745 int err;
746
Al Viroc5322222010-06-06 20:42:10 -0400747 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700748 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400749 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400750 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700751 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 }
753 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400754 __putname(from_name);
755 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700756 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757}
758
Al Viro10556cb2011-06-20 19:28:19 -0400759int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
761 char *name;
762 int r = 0, w = 0, x = 0, err;
763
Al Viro10556cb2011-06-20 19:28:19 -0400764 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100765 return -ECHILD;
766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if (desired & MAY_READ) r = 1;
768 if (desired & MAY_WRITE) w = 1;
769 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400770 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700771 if (name == NULL)
772 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
774 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700775 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 err = 0;
777 else
778 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400779 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700780 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400781 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return err;
783}
784
785int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
786{
Christoph Hellwig10257742010-06-04 11:30:02 +0200787 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 struct hostfs_iattr attrs;
789 char *name;
790 int err;
791
Christoph Hellwig10257742010-06-04 11:30:02 +0200792 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700793
Christoph Hellwig10257742010-06-04 11:30:02 +0200794 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (err)
796 return err;
797
Jeff Dike84b3db02007-10-16 01:27:13 -0700798 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 attr->ia_valid &= ~ATTR_SIZE;
800
801 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700802 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 attrs.ia_valid |= HOSTFS_ATTR_MODE;
804 attrs.ia_mode = attr->ia_mode;
805 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700806 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800808 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700810 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800812 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700814 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
816 attrs.ia_size = attr->ia_size;
817 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700818 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
820 attrs.ia_atime = attr->ia_atime;
821 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700822 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
824 attrs.ia_mtime = attr->ia_mtime;
825 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700826 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
828 attrs.ia_ctime = attr->ia_ctime;
829 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700830 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
832 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700833 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
835 }
Al Viroc5322222010-06-06 20:42:10 -0400836 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700837 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700838 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700839 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400840 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700841 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700842 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Christoph Hellwig10257742010-06-04 11:30:02 +0200844 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200845 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200846 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200847
848 setattr_copy(inode, attr);
849 mark_inode_dirty(inode);
850 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851}
852
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800853static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 .permission = hostfs_permission,
855 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856};
857
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800858static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 .create = hostfs_create,
860 .lookup = hostfs_lookup,
861 .link = hostfs_link,
862 .unlink = hostfs_unlink,
863 .symlink = hostfs_symlink,
864 .mkdir = hostfs_mkdir,
865 .rmdir = hostfs_rmdir,
866 .mknod = hostfs_mknod,
867 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 .permission = hostfs_permission,
869 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870};
871
Al Virod0352d32010-06-06 21:51:16 -0400872static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873{
Al Virod0352d32010-06-06 21:51:16 -0400874 char *link = __getname();
875 if (link) {
876 char *path = dentry_name(dentry);
877 int err = -ENOMEM;
878 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400879 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400880 if (err == PATH_MAX)
881 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400882 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400883 }
884 if (err < 0) {
885 __putname(link);
886 link = ERR_PTR(err);
887 }
888 } else {
889 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 }
Al Virod0352d32010-06-06 21:51:16 -0400891
892 nd_set_link(nd, link);
893 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894}
895
Al Virod0352d32010-06-06 21:51:16 -0400896static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
897{
898 char *s = nd_get_link(nd);
899 if (!IS_ERR(s))
900 __putname(s);
901}
902
903static const struct inode_operations hostfs_link_iops = {
904 .readlink = generic_readlink,
905 .follow_link = hostfs_follow_link,
906 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907};
908
909static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
910{
911 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700912 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 int err;
914
915 sb->s_blocksize = 1024;
916 sb->s_blocksize_bits = 10;
917 sb->s_magic = HOSTFS_SUPER_MAGIC;
918 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400919 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700920 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800922 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700923 if (req_root == NULL)
924 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400927 sb->s_fs_info = host_root_path =
928 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700929 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 goto out;
931
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700932 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
Al Viro52b209f72010-06-06 18:43:19 -0400934 root_inode = new_inode(sb);
935 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400936 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
Al Viro4754b822010-06-06 20:33:12 -0400938 err = read_name(root_inode, host_root_path);
939 if (err)
940 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400941
Al Viro4754b822010-06-06 20:33:12 -0400942 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400943 char *name = follow_link(host_root_path);
944 if (IS_ERR(name))
945 err = PTR_ERR(name);
946 else
947 err = read_name(root_inode, name);
948 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400949 if (err)
950 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500954 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700955 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500956 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Jeff Dikef1adc052007-05-08 00:23:18 -0700958 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Jeff Dikef1adc052007-05-08 00:23:18 -0700960out_put:
961 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700962out:
963 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964}
965
Al Viro3c26ff62010-07-25 11:46:36 +0400966static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700967 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400968 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
Al Viro3c26ff62010-07-25 11:46:36 +0400970 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971}
972
Al Viro601d2c32010-06-06 17:53:01 -0400973static void hostfs_kill_sb(struct super_block *s)
974{
975 kill_anon_super(s);
976 kfree(s->s_fs_info);
977}
978
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979static struct file_system_type hostfs_type = {
980 .owner = THIS_MODULE,
981 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400982 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400983 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 .fs_flags = 0,
985};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -0700986MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988static int __init init_hostfs(void)
989{
Jeff Dikef1adc052007-05-08 00:23:18 -0700990 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
993static void __exit exit_hostfs(void)
994{
995 unregister_filesystem(&hostfs_type);
996}
997
998module_init(init_hostfs)
999module_exit(exit_hostfs)
1000MODULE_LICENSE("GPL");