blob: 3841fb1ca5a2c2d8b3334f1d393521453db5ee91 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jeff Dikef1adc052007-05-08 00:23:18 -07002 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 *
5 * Ported the filesystem routines to 2.5.
6 * 2003-02-10 Petr Baudis <pasky@ucw.cz>
7 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/module.h>
Jeff Dike84b3db02007-10-16 01:27:13 -070011#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/statfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -080015#include <linux/seq_file.h>
Jiri Kosina6966a972008-02-09 00:10:14 -080016#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "hostfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "init.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070019#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
21struct hostfs_inode_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 int fd;
Al Viroaeb5d722008-09-02 15:28:45 -040023 fmode_t mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 struct inode vfs_inode;
25};
26
27static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
28{
Jeff Dikef1adc052007-05-08 00:23:18 -070029 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070030}
31
Josef Sipek680b0da2006-12-08 02:37:05 -080032#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Al Viroe16404e2009-02-20 05:55:13 +000034static int hostfs_d_delete(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035{
Jeff Dikef1adc052007-05-08 00:23:18 -070036 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070037}
38
Al Viroe16404e2009-02-20 05:55:13 +000039static const struct dentry_operations hostfs_dentry_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 .d_delete = hostfs_d_delete,
41};
42
43/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080044static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070045static int append = 0;
46
47#define HOSTFS_SUPER_MAGIC 0x00c0ffee
48
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080049static const struct inode_operations hostfs_iops;
50static const struct inode_operations hostfs_dir_iops;
Christoph Hellwigf5e54d62006-06-28 04:26:44 -070051static const struct address_space_operations hostfs_link_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#ifndef MODULE
54static int __init hostfs_args(char *options, int *add)
55{
56 char *ptr;
57
58 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070059 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070061 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 root_ino = options;
63
64 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070065 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070067 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070069 if (*options != '\0') {
70 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 append = 1;
72 else printf("hostfs_args - unsupported option - %s\n",
73 options);
74 }
75 options = ptr;
76 }
Jeff Dikef1adc052007-05-08 00:23:18 -070077 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
80__uml_setup("hostfs=", hostfs_args,
81"hostfs=<root dir>,<flags>,...\n"
82" This is used to set hostfs parameters. The root directory argument\n"
83" is used to confine all hostfs mounts to within the specified directory\n"
84" tree on the host. If this isn't specified, then a user inside UML can\n"
85" mount anything on the host that's accessible to the user that's running\n"
86" it.\n"
87" The only flag currently supported is 'append', which specifies that all\n"
88" files opened by hostfs will be opened in append mode.\n\n"
89);
90#endif
91
Al Viroc5322222010-06-06 20:42:10 -040092static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 struct dentry *parent;
95 char *root, *name;
96 int len;
97
98 len = 0;
99 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700100 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 len += parent->d_name.len + 1;
102 parent = parent->d_parent;
103 }
104
Al Viro601d2c32010-06-06 17:53:01 -0400105 root = parent->d_sb->s_fs_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 len += strlen(root);
Al Viroc5322222010-06-06 20:42:10 -0400107 name = kmalloc(len + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700108 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700109 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
111 name[len] = '\0';
112 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700113 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 len -= parent->d_name.len + 1;
115 name[len] = '/';
116 strncpy(&name[len + 1], parent->d_name.name,
117 parent->d_name.len);
118 parent = parent->d_parent;
119 }
120 strncpy(name, root, strlen(root));
Jeff Dikef1adc052007-05-08 00:23:18 -0700121 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
Al Viroc5322222010-06-06 20:42:10 -0400124static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
126 struct dentry *dentry;
127
128 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
Al Viroc5322222010-06-06 20:42:10 -0400129 return dentry_name(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130}
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static char *follow_link(char *link)
133{
134 int len, n;
135 char *name, *resolved, *end;
136
137 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700138 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 n = -ENOMEM;
140 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700141 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 goto out;
143
WANG Congea7e7432008-11-19 15:36:46 -0800144 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700145 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 break;
147 len *= 2;
148 kfree(name);
149 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700150 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 goto out_free;
152
Jeff Dike84b3db02007-10-16 01:27:13 -0700153 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700154 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700157 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700158 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
160 *(end + 1) = '\0';
161 len = strlen(link) + strlen(name) + 1;
162
163 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700164 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 n = -ENOMEM;
166 goto out_free;
167 }
168
169 sprintf(resolved, "%s%s", link, name);
170 kfree(name);
171 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700172 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174 out_free:
175 kfree(name);
176 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700177 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178}
179
David Howells0a370e52008-02-07 00:15:50 -0800180static struct inode *hostfs_iget(struct super_block *sb)
181{
Al Viro52b209f2010-06-06 18:43:19 -0400182 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800183 if (!inode)
184 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800185 return inode;
186}
187
David Howells726c3342006-06-23 02:02:58 -0700188int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189{
Jeff Dike84b3db02007-10-16 01:27:13 -0700190 /*
191 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 * struct statfs still has 32-bit versions for most of these fields,
193 * so we convert them here
194 */
195 int err;
196 long long f_blocks;
197 long long f_bfree;
198 long long f_bavail;
199 long long f_files;
200 long long f_ffree;
201
Al Viro601d2c32010-06-06 17:53:01 -0400202 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
204 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
205 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700206 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700207 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 sf->f_blocks = f_blocks;
209 sf->f_bfree = f_bfree;
210 sf->f_bavail = f_bavail;
211 sf->f_files = f_files;
212 sf->f_ffree = f_ffree;
213 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700214 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215}
216
217static struct inode *hostfs_alloc_inode(struct super_block *sb)
218{
219 struct hostfs_inode_info *hi;
220
Al Viro601d2c32010-06-06 17:53:01 -0400221 hi = kzalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700222 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700223 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400224 hi->fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700226 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
228
Al Viroe971a6d2010-06-06 15:16:17 -0400229static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
Mark Fashehfef26652005-09-09 13:01:31 -0700231 truncate_inode_pages(&inode->i_data, 0);
Al Viroe971a6d2010-06-06 15:16:17 -0400232 end_writeback(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700233 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 close_file(&HOSTFS_I(inode)->fd);
235 HOSTFS_I(inode)->fd = -1;
236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237}
238
239static void hostfs_destroy_inode(struct inode *inode)
240{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 kfree(HOSTFS_I(inode));
242}
243
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800244static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
245{
Al Viro601d2c32010-06-06 17:53:01 -0400246 const char *root_path = vfs->mnt_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800247 size_t offset = strlen(root_ino) + 1;
248
249 if (strlen(root_path) > offset)
250 seq_printf(seq, ",%s", root_path + offset);
251
252 return 0;
253}
254
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800255static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400258 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800260 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261};
262
263int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
264{
265 void *dir;
266 char *name;
267 unsigned long long next, ino;
268 int error, len;
269
Al Viroc5322222010-06-06 20:42:10 -0400270 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700271 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700272 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 dir = open_dir(name, &error);
274 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700275 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700276 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700278 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 error = (*filldir)(ent, name, len, file->f_pos,
280 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700281 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 file->f_pos = next;
283 }
284 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700285 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286}
287
288int hostfs_file_open(struct inode *ino, struct file *file)
289{
290 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400291 fmode_t mode = 0;
292 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700295 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700296 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Jeff Dike84b3db02007-10-16 01:27:13 -0700298 /*
299 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 * so this resets things and reopens the file with the new access.
301 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700302 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 close_file(&HOSTFS_I(ino)->fd);
304 HOSTFS_I(ino)->fd = -1;
305 }
306
307 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700308 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700310 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700312 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 r = 1;
314
Al Viroc5322222010-06-06 20:42:10 -0400315 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700316 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700317 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 fd = open_file(name, r, w, append);
320 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700321 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700322 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 FILE_HOSTFS_I(file)->fd = fd;
324
Jeff Dikef1adc052007-05-08 00:23:18 -0700325 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200328int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200330 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800333static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700335 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200336 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 .aio_read = generic_file_aio_read,
338 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700339 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 .mmap = generic_file_mmap,
341 .open = hostfs_file_open,
342 .release = NULL,
343 .fsync = hostfs_fsync,
344};
345
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800346static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 .llseek = generic_file_llseek,
348 .readdir = hostfs_readdir,
349 .read = generic_read_dir,
350};
351
352int hostfs_writepage(struct page *page, struct writeback_control *wbc)
353{
354 struct address_space *mapping = page->mapping;
355 struct inode *inode = mapping->host;
356 char *buffer;
357 unsigned long long base;
358 int count = PAGE_CACHE_SIZE;
359 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
360 int err;
361
362 if (page->index >= end_index)
363 count = inode->i_size & (PAGE_CACHE_SIZE-1);
364
365 buffer = kmap(page);
366 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
367
368 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700369 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 ClearPageUptodate(page);
371 goto out;
372 }
373
374 if (base > inode->i_size)
375 inode->i_size = base;
376
377 if (PageError(page))
378 ClearPageError(page);
379 err = 0;
380
381 out:
382 kunmap(page);
383
384 unlock_page(page);
385 return err;
386}
387
388int hostfs_readpage(struct file *file, struct page *page)
389{
390 char *buffer;
391 long long start;
392 int err = 0;
393
394 start = (long long) page->index << PAGE_CACHE_SHIFT;
395 buffer = kmap(page);
396 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
397 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700398 if (err < 0)
399 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
402
403 flush_dcache_page(page);
404 SetPageUptodate(page);
405 if (PageError(page)) ClearPageError(page);
406 err = 0;
407 out:
408 kunmap(page);
409 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700410 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
Nick Pigginae361ff2007-10-16 01:25:17 -0700413int hostfs_write_begin(struct file *file, struct address_space *mapping,
414 loff_t pos, unsigned len, unsigned flags,
415 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416{
Nick Pigginae361ff2007-10-16 01:25:17 -0700417 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Nick Piggin54566b22009-01-04 12:00:53 -0800419 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700420 if (!*pagep)
421 return -ENOMEM;
422 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423}
424
Nick Pigginae361ff2007-10-16 01:25:17 -0700425int hostfs_write_end(struct file *file, struct address_space *mapping,
426 loff_t pos, unsigned len, unsigned copied,
427 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700430 void *buffer;
431 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
432 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700435 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700437
438 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
439 SetPageUptodate(page);
440
Jeff Dike84b3db02007-10-16 01:27:13 -0700441 /*
442 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700443 * i_size against the last byte written.
444 */
445 if (err > 0 && (pos > inode->i_size))
446 inode->i_size = pos;
447 unlock_page(page);
448 page_cache_release(page);
449
Jeff Dikef1adc052007-05-08 00:23:18 -0700450 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451}
452
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700453static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 .writepage = hostfs_writepage,
455 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700456 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700457 .write_begin = hostfs_write_begin,
458 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459};
460
Al Viro4754b822010-06-06 20:33:12 -0400461static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Al Viro4754b822010-06-06 20:33:12 -0400463 dev_t rdev;
464 struct hostfs_stat st;
465 int err = stat_file(name, &st, -1);
466 if (err)
467 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Al Viro5e2df282010-06-06 19:38:18 -0400469 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400470 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Al Viro4754b822010-06-06 20:33:12 -0400472 switch (st.mode & S_IFMT) {
473 case S_IFLNK:
474 ino->i_op = &page_symlink_inode_operations;
475 ino->i_mapping->a_ops = &hostfs_link_aops;
476 break;
477 case S_IFDIR:
478 ino->i_op = &hostfs_dir_iops;
479 ino->i_fop = &hostfs_dir_fops;
480 break;
481 case S_IFCHR:
482 case S_IFBLK:
483 case S_IFIFO:
484 case S_IFSOCK:
485 init_special_inode(ino, st.mode & S_IFMT, rdev);
486 ino->i_op = &hostfs_iops;
487 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Al Viro4754b822010-06-06 20:33:12 -0400489 default:
490 ino->i_op = &hostfs_iops;
491 ino->i_fop = &hostfs_file_fops;
492 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 }
Al Viro4754b822010-06-06 20:33:12 -0400494
495 ino->i_ino = st.ino;
496 ino->i_mode = st.mode;
497 ino->i_nlink = st.nlink;
498 ino->i_uid = st.uid;
499 ino->i_gid = st.gid;
500 ino->i_atime = st.atime;
501 ino->i_mtime = st.mtime;
502 ino->i_ctime = st.ctime;
503 ino->i_size = st.size;
504 ino->i_blocks = st.blocks;
505 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
508int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700509 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 struct inode *inode;
512 char *name;
513 int error, fd;
514
David Howells0a370e52008-02-07 00:15:50 -0800515 inode = hostfs_iget(dir->i_sb);
516 if (IS_ERR(inode)) {
517 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700518 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400522 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700523 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 goto out_put;
525
526 fd = file_create(name,
527 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
528 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
529 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400530 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400532 else
Al Viro5e2df282010-06-06 19:38:18 -0400533 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
535 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700536 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 goto out_put;
538
539 HOSTFS_I(inode)->fd = fd;
540 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
541 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700542 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 out_put:
545 iput(inode);
546 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700547 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548}
549
550struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700551 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
553 struct inode *inode;
554 char *name;
555 int err;
556
David Howells0a370e52008-02-07 00:15:50 -0800557 inode = hostfs_iget(ino->i_sb);
558 if (IS_ERR(inode)) {
559 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400564 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700565 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 goto out_put;
567
568 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700571 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 iput(inode);
573 inode = NULL;
574 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700575 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 goto out_put;
577
578 d_add(dentry, inode);
579 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700580 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
582 out_put:
583 iput(inode);
584 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700585 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
589{
Jeff Dikef1adc052007-05-08 00:23:18 -0700590 char *from_name, *to_name;
591 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Al Viroc5322222010-06-06 20:42:10 -0400593 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700594 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400595 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700596 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700598 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700600 err = link_file(to_name, from_name);
601 kfree(from_name);
602 kfree(to_name);
603 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604}
605
606int hostfs_unlink(struct inode *ino, struct dentry *dentry)
607{
608 char *file;
609 int err;
610
Al Viroc5322222010-06-06 20:42:10 -0400611 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700612 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700613 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700614 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 err = unlink_file(file);
617 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700618 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619}
620
621int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
622{
623 char *file;
624 int err;
625
Al Viroc5322222010-06-06 20:42:10 -0400626 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700627 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 err = make_symlink(file, to);
629 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700630 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
633int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
634{
635 char *file;
636 int err;
637
Al Viroc5322222010-06-06 20:42:10 -0400638 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 err = do_mkdir(file, mode);
641 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700642 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643}
644
645int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
646{
647 char *file;
648 int err;
649
Al Viroc5322222010-06-06 20:42:10 -0400650 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700651 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 err = do_rmdir(file);
653 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700654 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
656
657int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
658{
659 struct inode *inode;
660 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800661 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
David Howells0a370e52008-02-07 00:15:50 -0800663 inode = hostfs_iget(dir->i_sb);
664 if (IS_ERR(inode)) {
665 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400670 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700671 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 goto out_put;
673
674 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800675 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700676 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 goto out_free;
678
679 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400680 if (err)
681 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700683 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 goto out_put;
685
686 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689 out_free:
690 kfree(name);
691 out_put:
692 iput(inode);
693 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700694 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
697int hostfs_rename(struct inode *from_ino, struct dentry *from,
698 struct inode *to_ino, struct dentry *to)
699{
700 char *from_name, *to_name;
701 int err;
702
Al Viroc5322222010-06-06 20:42:10 -0400703 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700704 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400705 if ((to_name = dentry_name(to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700707 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
709 err = rename_file(from_name, to_name);
710 kfree(from_name);
711 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700712 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713}
714
Al Viroe6305c42008-07-15 21:03:57 -0400715int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
717 char *name;
718 int r = 0, w = 0, x = 0, err;
719
720 if (desired & MAY_READ) r = 1;
721 if (desired & MAY_WRITE) w = 1;
722 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400723 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700724 if (name == NULL)
725 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700728 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 err = 0;
730 else
731 err = access_file(name, r, w, x);
732 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700733 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 err = generic_permission(ino, desired, NULL);
735 return err;
736}
737
738int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
739{
Christoph Hellwig10257742010-06-04 11:30:02 +0200740 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 struct hostfs_iattr attrs;
742 char *name;
743 int err;
744
Christoph Hellwig10257742010-06-04 11:30:02 +0200745 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700746
Christoph Hellwig10257742010-06-04 11:30:02 +0200747 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 if (err)
749 return err;
750
Jeff Dike84b3db02007-10-16 01:27:13 -0700751 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 attr->ia_valid &= ~ATTR_SIZE;
753
754 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700755 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 attrs.ia_valid |= HOSTFS_ATTR_MODE;
757 attrs.ia_mode = attr->ia_mode;
758 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700759 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 attrs.ia_valid |= HOSTFS_ATTR_UID;
761 attrs.ia_uid = attr->ia_uid;
762 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700763 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 attrs.ia_valid |= HOSTFS_ATTR_GID;
765 attrs.ia_gid = attr->ia_gid;
766 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700767 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
769 attrs.ia_size = attr->ia_size;
770 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700771 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
773 attrs.ia_atime = attr->ia_atime;
774 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700775 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
777 attrs.ia_mtime = attr->ia_mtime;
778 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700779 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
781 attrs.ia_ctime = attr->ia_ctime;
782 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700783 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
785 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700786 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
788 }
Al Viroc5322222010-06-06 20:42:10 -0400789 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700790 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700791 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700792 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700794 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700795 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Christoph Hellwig10257742010-06-04 11:30:02 +0200797 if ((attr->ia_valid & ATTR_SIZE) &&
798 attr->ia_size != i_size_read(inode)) {
799 int error;
800
801 error = vmtruncate(inode, attr->ia_size);
802 if (err)
803 return err;
804 }
805
806 setattr_copy(inode, attr);
807 mark_inode_dirty(inode);
808 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800811static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 .create = hostfs_create,
813 .link = hostfs_link,
814 .unlink = hostfs_unlink,
815 .symlink = hostfs_symlink,
816 .mkdir = hostfs_mkdir,
817 .rmdir = hostfs_rmdir,
818 .mknod = hostfs_mknod,
819 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 .permission = hostfs_permission,
821 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822};
823
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800824static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 .create = hostfs_create,
826 .lookup = hostfs_lookup,
827 .link = hostfs_link,
828 .unlink = hostfs_unlink,
829 .symlink = hostfs_symlink,
830 .mkdir = hostfs_mkdir,
831 .rmdir = hostfs_rmdir,
832 .mknod = hostfs_mknod,
833 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 .permission = hostfs_permission,
835 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836};
837
838int hostfs_link_readpage(struct file *file, struct page *page)
839{
840 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 int err;
842
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 buffer = kmap(page);
Al Viroc5322222010-06-06 20:42:10 -0400844 name = inode_name(page->mapping->host);
Jeff Dike84b3db02007-10-16 01:27:13 -0700845 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700846 return -ENOMEM;
WANG Congea7e7432008-11-19 15:36:46 -0800847 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700849 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700851 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 flush_dcache_page(page);
853 SetPageUptodate(page);
854 if (PageError(page)) ClearPageError(page);
855 err = 0;
856 }
857 kunmap(page);
858 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700859 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700862static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 .readpage = hostfs_link_readpage,
864};
865
866static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
867{
868 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700869 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 int err;
871
872 sb->s_blocksize = 1024;
873 sb->s_blocksize_bits = 10;
874 sb->s_magic = HOSTFS_SUPER_MAGIC;
875 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700876 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800878 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700879 if (req_root == NULL)
880 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400883 sb->s_fs_info = host_root_path =
884 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700885 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 goto out;
887
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700888 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
Al Viro52b209f2010-06-06 18:43:19 -0400890 root_inode = new_inode(sb);
891 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400892 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Al Viro4754b822010-06-06 20:33:12 -0400894 err = read_name(root_inode, host_root_path);
895 if (err)
896 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400897
Al Viro4754b822010-06-06 20:33:12 -0400898 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400899 char *name = follow_link(host_root_path);
900 if (IS_ERR(name))
901 err = PTR_ERR(name);
902 else
903 err = read_name(root_inode, name);
904 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400905 if (err)
906 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400907 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 err = -ENOMEM;
910 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700911 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 goto out_put;
913
Jeff Dikef1adc052007-05-08 00:23:18 -0700914 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
Jeff Dikef1adc052007-05-08 00:23:18 -0700916out_put:
917 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700918out:
919 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920}
921
David Howells454e2392006-06-23 02:02:57 -0700922static int hostfs_read_sb(struct file_system_type *type,
923 int flags, const char *dev_name,
924 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
David Howells454e2392006-06-23 02:02:57 -0700926 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927}
928
Al Viro601d2c32010-06-06 17:53:01 -0400929static void hostfs_kill_sb(struct super_block *s)
930{
931 kill_anon_super(s);
932 kfree(s->s_fs_info);
933}
934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935static struct file_system_type hostfs_type = {
936 .owner = THIS_MODULE,
937 .name = "hostfs",
938 .get_sb = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400939 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 .fs_flags = 0,
941};
942
943static int __init init_hostfs(void)
944{
Jeff Dikef1adc052007-05-08 00:23:18 -0700945 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946}
947
948static void __exit exit_hostfs(void)
949{
950 unregister_filesystem(&hostfs_type);
951}
952
953module_init(init_hostfs)
954module_exit(exit_hostfs)
955MODULE_LICENSE("GPL");