blob: b29a2b878f46686444af050561200baf1d092efb [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
92static char *dentry_name(struct dentry *dentry, int extra)
93{
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);
107 name = kmalloc(len + extra + 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
124static char *inode_name(struct inode *ino, int extra)
125{
126 struct dentry *dentry;
127
128 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
Jeff Dikef1adc052007-05-08 00:23:18 -0700129 return dentry_name(dentry, extra);
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 Viro52b209f72010-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
Josef Sipek680b0da2006-12-08 02:37:05 -0800270 name = dentry_name(file->f_path.dentry, 0);
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
Josef Sipek680b0da2006-12-08 02:37:05 -0800315 name = dentry_name(file->f_path.dentry, 0);
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;
522 name = dentry_name(dentry, 0);
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;
564 name = dentry_name(dentry, 0);
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
588static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
589{
Jeff Dikef1adc052007-05-08 00:23:18 -0700590 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 int len;
592
593 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700594 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700595 return NULL;
596 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700598 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700600 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
603int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
604{
Jeff Dikef1adc052007-05-08 00:23:18 -0700605 char *from_name, *to_name;
606 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Jeff Dike84b3db02007-10-16 01:27:13 -0700608 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700609 return -ENOMEM;
610 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700611 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700613 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700615 err = link_file(to_name, from_name);
616 kfree(from_name);
617 kfree(to_name);
618 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619}
620
621int hostfs_unlink(struct inode *ino, struct dentry *dentry)
622{
623 char *file;
624 int err;
625
Jeff Dike84b3db02007-10-16 01:27:13 -0700626 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700627 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700628 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700629 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
631 err = unlink_file(file);
632 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700633 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
635
636int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
637{
638 char *file;
639 int err;
640
Jeff Dike84b3db02007-10-16 01:27:13 -0700641 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700642 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 err = make_symlink(file, to);
644 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700645 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646}
647
648int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
649{
650 char *file;
651 int err;
652
Jeff Dike84b3db02007-10-16 01:27:13 -0700653 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700654 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 err = do_mkdir(file, mode);
656 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700657 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658}
659
660int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
661{
662 char *file;
663 int err;
664
Jeff Dike84b3db02007-10-16 01:27:13 -0700665 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700666 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 err = do_rmdir(file);
668 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700669 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670}
671
672int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
673{
674 struct inode *inode;
675 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800676 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
David Howells0a370e52008-02-07 00:15:50 -0800678 inode = hostfs_iget(dir->i_sb);
679 if (IS_ERR(inode)) {
680 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 err = -ENOMEM;
685 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700686 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 goto out_put;
688
689 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800690 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700691 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 goto out_free;
693
694 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400695 if (err)
696 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700698 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 goto out_put;
700
701 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700702 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
704 out_free:
705 kfree(name);
706 out_put:
707 iput(inode);
708 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700709 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710}
711
712int hostfs_rename(struct inode *from_ino, struct dentry *from,
713 struct inode *to_ino, struct dentry *to)
714{
715 char *from_name, *to_name;
716 int err;
717
Jeff Dike84b3db02007-10-16 01:27:13 -0700718 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700719 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700720 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700722 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724 err = rename_file(from_name, to_name);
725 kfree(from_name);
726 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700727 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728}
729
Al Viroe6305c42008-07-15 21:03:57 -0400730int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731{
732 char *name;
733 int r = 0, w = 0, x = 0, err;
734
735 if (desired & MAY_READ) r = 1;
736 if (desired & MAY_WRITE) w = 1;
737 if (desired & MAY_EXEC) x = 1;
738 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700739 if (name == NULL)
740 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700743 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 err = 0;
745 else
746 err = access_file(name, r, w, x);
747 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700748 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 err = generic_permission(ino, desired, NULL);
750 return err;
751}
752
753int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
754{
Christoph Hellwig10257742010-06-04 11:30:02 +0200755 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 struct hostfs_iattr attrs;
757 char *name;
758 int err;
759
Christoph Hellwig10257742010-06-04 11:30:02 +0200760 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700761
Christoph Hellwig10257742010-06-04 11:30:02 +0200762 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 if (err)
764 return err;
765
Jeff Dike84b3db02007-10-16 01:27:13 -0700766 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 attr->ia_valid &= ~ATTR_SIZE;
768
769 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700770 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 attrs.ia_valid |= HOSTFS_ATTR_MODE;
772 attrs.ia_mode = attr->ia_mode;
773 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700774 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 attrs.ia_valid |= HOSTFS_ATTR_UID;
776 attrs.ia_uid = attr->ia_uid;
777 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700778 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 attrs.ia_valid |= HOSTFS_ATTR_GID;
780 attrs.ia_gid = attr->ia_gid;
781 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700782 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
784 attrs.ia_size = attr->ia_size;
785 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700786 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
788 attrs.ia_atime = attr->ia_atime;
789 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700790 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
792 attrs.ia_mtime = attr->ia_mtime;
793 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700794 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
796 attrs.ia_ctime = attr->ia_ctime;
797 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700798 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
800 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700801 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
803 }
804 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700805 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700806 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700807 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700809 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700810 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Christoph Hellwig10257742010-06-04 11:30:02 +0200812 if ((attr->ia_valid & ATTR_SIZE) &&
813 attr->ia_size != i_size_read(inode)) {
814 int error;
815
816 error = vmtruncate(inode, attr->ia_size);
817 if (err)
818 return err;
819 }
820
821 setattr_copy(inode, attr);
822 mark_inode_dirty(inode);
823 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824}
825
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800826static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 .create = hostfs_create,
828 .link = hostfs_link,
829 .unlink = hostfs_unlink,
830 .symlink = hostfs_symlink,
831 .mkdir = hostfs_mkdir,
832 .rmdir = hostfs_rmdir,
833 .mknod = hostfs_mknod,
834 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 .permission = hostfs_permission,
836 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837};
838
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800839static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 .create = hostfs_create,
841 .lookup = hostfs_lookup,
842 .link = hostfs_link,
843 .unlink = hostfs_unlink,
844 .symlink = hostfs_symlink,
845 .mkdir = hostfs_mkdir,
846 .rmdir = hostfs_rmdir,
847 .mknod = hostfs_mknod,
848 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 .permission = hostfs_permission,
850 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851};
852
853int hostfs_link_readpage(struct file *file, struct page *page)
854{
855 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 int err;
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 buffer = kmap(page);
859 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700860 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700861 return -ENOMEM;
WANG Congea7e7432008-11-19 15:36:46 -0800862 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700864 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700866 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 flush_dcache_page(page);
868 SetPageUptodate(page);
869 if (PageError(page)) ClearPageError(page);
870 err = 0;
871 }
872 kunmap(page);
873 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700874 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875}
876
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700877static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 .readpage = hostfs_link_readpage,
879};
880
881static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
882{
883 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700884 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 int err;
886
887 sb->s_blocksize = 1024;
888 sb->s_blocksize_bits = 10;
889 sb->s_magic = HOSTFS_SUPER_MAGIC;
890 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700891 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800893 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700894 if (req_root == NULL)
895 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
897 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400898 sb->s_fs_info = host_root_path =
899 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700900 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 goto out;
902
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700903 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Al Viro52b209f72010-06-06 18:43:19 -0400905 root_inode = new_inode(sb);
906 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400907 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Al Viro4754b822010-06-06 20:33:12 -0400909 err = read_name(root_inode, host_root_path);
910 if (err)
911 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400912
Al Viro4754b822010-06-06 20:33:12 -0400913 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400914 char *name = follow_link(host_root_path);
915 if (IS_ERR(name))
916 err = PTR_ERR(name);
917 else
918 err = read_name(root_inode, name);
919 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400920 if (err)
921 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 err = -ENOMEM;
925 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700926 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 goto out_put;
928
Jeff Dikef1adc052007-05-08 00:23:18 -0700929 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Jeff Dikef1adc052007-05-08 00:23:18 -0700931out_put:
932 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700933out:
934 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935}
936
David Howells454e2392006-06-23 02:02:57 -0700937static int hostfs_read_sb(struct file_system_type *type,
938 int flags, const char *dev_name,
939 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940{
David Howells454e2392006-06-23 02:02:57 -0700941 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942}
943
Al Viro601d2c32010-06-06 17:53:01 -0400944static void hostfs_kill_sb(struct super_block *s)
945{
946 kill_anon_super(s);
947 kfree(s->s_fs_info);
948}
949
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950static struct file_system_type hostfs_type = {
951 .owner = THIS_MODULE,
952 .name = "hostfs",
953 .get_sb = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400954 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 .fs_flags = 0,
956};
957
958static int __init init_hostfs(void)
959{
Jeff Dikef1adc052007-05-08 00:23:18 -0700960 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961}
962
963static void __exit exit_hostfs(void)
964{
965 unregister_filesystem(&hostfs_type);
966}
967
968module_init(init_hostfs)
969module_exit(exit_hostfs)
970MODULE_LICENSE("GPL");