blob: 79783a0b2f4d0280069c791315ad847724aeeba4 [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>
Al Virod0352d32010-06-06 21:51:16 -040017#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "hostfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include "init.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070020#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22struct hostfs_inode_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 int fd;
Al Viroaeb5d722008-09-02 15:28:45 -040024 fmode_t mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 struct inode vfs_inode;
26};
27
28static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
29{
Jeff Dikef1adc052007-05-08 00:23:18 -070030 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031}
32
Josef Sipek680b0da2006-12-08 02:37:05 -080033#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Al Viroe16404e2009-02-20 05:55:13 +000035static int hostfs_d_delete(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070036{
Jeff Dikef1adc052007-05-08 00:23:18 -070037 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038}
39
Al Viroe16404e2009-02-20 05:55:13 +000040static const struct dentry_operations hostfs_dentry_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 .d_delete = hostfs_d_delete,
42};
43
44/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080045static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070046static int append = 0;
47
48#define HOSTFS_SUPER_MAGIC 0x00c0ffee
49
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080050static const struct inode_operations hostfs_iops;
51static const struct inode_operations hostfs_dir_iops;
Al Virod0352d32010-06-06 21:51:16 -040052static const struct inode_operations hostfs_link_iops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54#ifndef MODULE
55static int __init hostfs_args(char *options, int *add)
56{
57 char *ptr;
58
59 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070060 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070062 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 root_ino = options;
64
65 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070066 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070068 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070070 if (*options != '\0') {
71 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 append = 1;
73 else printf("hostfs_args - unsupported option - %s\n",
74 options);
75 }
76 options = ptr;
77 }
Jeff Dikef1adc052007-05-08 00:23:18 -070078 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079}
80
81__uml_setup("hostfs=", hostfs_args,
82"hostfs=<root dir>,<flags>,...\n"
83" This is used to set hostfs parameters. The root directory argument\n"
84" is used to confine all hostfs mounts to within the specified directory\n"
85" tree on the host. If this isn't specified, then a user inside UML can\n"
86" mount anything on the host that's accessible to the user that's running\n"
87" it.\n"
88" The only flag currently supported is 'append', which specifies that all\n"
89" files opened by hostfs will be opened in append mode.\n\n"
90);
91#endif
92
Al Viroe9193052010-06-06 23:16:34 -040093static char *__dentry_name(struct dentry *dentry, char *name)
94{
95 char *p = __dentry_path(dentry, name, PATH_MAX);
96 char *root;
97 size_t len;
98
99 spin_unlock(&dcache_lock);
100
101 root = dentry->d_sb->s_fs_info;
102 len = strlen(root);
103 if (IS_ERR(p)) {
104 __putname(name);
105 return NULL;
106 }
107 strncpy(name, root, PATH_MAX);
108 if (len > p - name) {
109 __putname(name);
110 return NULL;
111 }
112 if (p > name + len) {
113 char *s = name + len;
114 while ((*s++ = *p++) != '\0')
115 ;
116 }
117 return name;
118}
119
Al Viroc5322222010-06-06 20:42:10 -0400120static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
Al Viroe9193052010-06-06 23:16:34 -0400122 char *name = __getname();
123 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700124 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Al Viroe9193052010-06-06 23:16:34 -0400126 spin_lock(&dcache_lock);
127 return __dentry_name(dentry, name); /* will unlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128}
129
Al Viroc5322222010-06-06 20:42:10 -0400130static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
132 struct dentry *dentry;
Al Viroe9193052010-06-06 23:16:34 -0400133 char *name = __getname();
134 if (!name)
135 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Al Viroe9193052010-06-06 23:16:34 -0400137 spin_lock(&dcache_lock);
138 if (list_empty(&ino->i_dentry)) {
139 spin_unlock(&dcache_lock);
140 __putname(name);
141 return NULL;
142 }
143 dentry = list_first_entry(&ino->i_dentry, struct dentry, d_alias);
144 return __dentry_name(dentry, name); /* will unlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145}
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static char *follow_link(char *link)
148{
149 int len, n;
150 char *name, *resolved, *end;
151
152 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700153 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 n = -ENOMEM;
155 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700156 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 goto out;
158
WANG Congea7e7432008-11-19 15:36:46 -0800159 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700160 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 break;
162 len *= 2;
163 kfree(name);
164 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700165 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 goto out_free;
167
Jeff Dike84b3db02007-10-16 01:27:13 -0700168 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700169 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700172 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700173 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175 *(end + 1) = '\0';
176 len = strlen(link) + strlen(name) + 1;
177
178 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700179 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 n = -ENOMEM;
181 goto out_free;
182 }
183
184 sprintf(resolved, "%s%s", link, name);
185 kfree(name);
186 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700187 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189 out_free:
190 kfree(name);
191 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700192 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
David Howells0a370e52008-02-07 00:15:50 -0800195static struct inode *hostfs_iget(struct super_block *sb)
196{
Al Viro52b209f2010-06-06 18:43:19 -0400197 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800198 if (!inode)
199 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800200 return inode;
201}
202
David Howells726c3342006-06-23 02:02:58 -0700203int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
Jeff Dike84b3db02007-10-16 01:27:13 -0700205 /*
206 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 * struct statfs still has 32-bit versions for most of these fields,
208 * so we convert them here
209 */
210 int err;
211 long long f_blocks;
212 long long f_bfree;
213 long long f_bavail;
214 long long f_files;
215 long long f_ffree;
216
Al Viro601d2c32010-06-06 17:53:01 -0400217 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
219 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
220 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700221 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700222 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 sf->f_blocks = f_blocks;
224 sf->f_bfree = f_bfree;
225 sf->f_bavail = f_bavail;
226 sf->f_files = f_files;
227 sf->f_ffree = f_ffree;
228 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700229 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230}
231
232static struct inode *hostfs_alloc_inode(struct super_block *sb)
233{
234 struct hostfs_inode_info *hi;
235
Al Viro601d2c32010-06-06 17:53:01 -0400236 hi = kzalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700237 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700238 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400239 hi->fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700241 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
Al Viroe971a6d2010-06-06 15:16:17 -0400244static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
Mark Fashehfef26652005-09-09 13:01:31 -0700246 truncate_inode_pages(&inode->i_data, 0);
Al Viroe971a6d2010-06-06 15:16:17 -0400247 end_writeback(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700248 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 close_file(&HOSTFS_I(inode)->fd);
250 HOSTFS_I(inode)->fd = -1;
251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252}
253
254static void hostfs_destroy_inode(struct inode *inode)
255{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 kfree(HOSTFS_I(inode));
257}
258
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800259static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
260{
Al Viro601d2c32010-06-06 17:53:01 -0400261 const char *root_path = vfs->mnt_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800262 size_t offset = strlen(root_ino) + 1;
263
264 if (strlen(root_path) > offset)
265 seq_printf(seq, ",%s", root_path + offset);
266
267 return 0;
268}
269
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800270static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400273 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800275 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276};
277
278int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
279{
280 void *dir;
281 char *name;
282 unsigned long long next, ino;
283 int error, len;
284
Al Viroc5322222010-06-06 20:42:10 -0400285 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700286 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700287 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400289 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700290 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700291 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700293 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 error = (*filldir)(ent, name, len, file->f_pos,
295 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700296 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 file->f_pos = next;
298 }
299 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700300 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
303int hostfs_file_open(struct inode *ino, struct file *file)
304{
305 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400306 fmode_t mode = 0;
307 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700310 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700311 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Jeff Dike84b3db02007-10-16 01:27:13 -0700313 /*
314 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 * so this resets things and reopens the file with the new access.
316 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700317 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 close_file(&HOSTFS_I(ino)->fd);
319 HOSTFS_I(ino)->fd = -1;
320 }
321
322 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700323 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700325 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700327 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 r = 1;
329
Al Viroc5322222010-06-06 20:42:10 -0400330 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700331 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700332 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
334 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400335 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700336 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700337 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 FILE_HOSTFS_I(file)->fd = fd;
339
Jeff Dikef1adc052007-05-08 00:23:18 -0700340 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341}
342
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200343int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200345 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346}
347
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800348static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700350 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200351 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 .aio_read = generic_file_aio_read,
353 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700354 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 .mmap = generic_file_mmap,
356 .open = hostfs_file_open,
357 .release = NULL,
358 .fsync = hostfs_fsync,
359};
360
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800361static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 .llseek = generic_file_llseek,
363 .readdir = hostfs_readdir,
364 .read = generic_read_dir,
365};
366
367int hostfs_writepage(struct page *page, struct writeback_control *wbc)
368{
369 struct address_space *mapping = page->mapping;
370 struct inode *inode = mapping->host;
371 char *buffer;
372 unsigned long long base;
373 int count = PAGE_CACHE_SIZE;
374 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
375 int err;
376
377 if (page->index >= end_index)
378 count = inode->i_size & (PAGE_CACHE_SIZE-1);
379
380 buffer = kmap(page);
381 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
382
383 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700384 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 ClearPageUptodate(page);
386 goto out;
387 }
388
389 if (base > inode->i_size)
390 inode->i_size = base;
391
392 if (PageError(page))
393 ClearPageError(page);
394 err = 0;
395
396 out:
397 kunmap(page);
398
399 unlock_page(page);
400 return err;
401}
402
403int hostfs_readpage(struct file *file, struct page *page)
404{
405 char *buffer;
406 long long start;
407 int err = 0;
408
409 start = (long long) page->index << PAGE_CACHE_SHIFT;
410 buffer = kmap(page);
411 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
412 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700413 if (err < 0)
414 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
417
418 flush_dcache_page(page);
419 SetPageUptodate(page);
420 if (PageError(page)) ClearPageError(page);
421 err = 0;
422 out:
423 kunmap(page);
424 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700425 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426}
427
Nick Pigginae361ff2007-10-16 01:25:17 -0700428int hostfs_write_begin(struct file *file, struct address_space *mapping,
429 loff_t pos, unsigned len, unsigned flags,
430 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
Nick Pigginae361ff2007-10-16 01:25:17 -0700432 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Nick Piggin54566b22009-01-04 12:00:53 -0800434 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700435 if (!*pagep)
436 return -ENOMEM;
437 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438}
439
Nick Pigginae361ff2007-10-16 01:25:17 -0700440int hostfs_write_end(struct file *file, struct address_space *mapping,
441 loff_t pos, unsigned len, unsigned copied,
442 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700445 void *buffer;
446 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
447 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700450 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700452
453 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
454 SetPageUptodate(page);
455
Jeff Dike84b3db02007-10-16 01:27:13 -0700456 /*
457 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700458 * i_size against the last byte written.
459 */
460 if (err > 0 && (pos > inode->i_size))
461 inode->i_size = pos;
462 unlock_page(page);
463 page_cache_release(page);
464
Jeff Dikef1adc052007-05-08 00:23:18 -0700465 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466}
467
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700468static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 .writepage = hostfs_writepage,
470 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700471 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700472 .write_begin = hostfs_write_begin,
473 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474};
475
Al Viro4754b822010-06-06 20:33:12 -0400476static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
Al Viro4754b822010-06-06 20:33:12 -0400478 dev_t rdev;
479 struct hostfs_stat st;
480 int err = stat_file(name, &st, -1);
481 if (err)
482 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Al Viro5e2df282010-06-06 19:38:18 -0400484 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400485 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Al Viro4754b822010-06-06 20:33:12 -0400487 switch (st.mode & S_IFMT) {
488 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400489 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400490 break;
491 case S_IFDIR:
492 ino->i_op = &hostfs_dir_iops;
493 ino->i_fop = &hostfs_dir_fops;
494 break;
495 case S_IFCHR:
496 case S_IFBLK:
497 case S_IFIFO:
498 case S_IFSOCK:
499 init_special_inode(ino, st.mode & S_IFMT, rdev);
500 ino->i_op = &hostfs_iops;
501 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Al Viro4754b822010-06-06 20:33:12 -0400503 default:
504 ino->i_op = &hostfs_iops;
505 ino->i_fop = &hostfs_file_fops;
506 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 }
Al Viro4754b822010-06-06 20:33:12 -0400508
509 ino->i_ino = st.ino;
510 ino->i_mode = st.mode;
511 ino->i_nlink = st.nlink;
512 ino->i_uid = st.uid;
513 ino->i_gid = st.gid;
514 ino->i_atime = st.atime;
515 ino->i_mtime = st.mtime;
516 ino->i_ctime = st.ctime;
517 ino->i_size = st.size;
518 ino->i_blocks = st.blocks;
519 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520}
521
522int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700523 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
525 struct inode *inode;
526 char *name;
527 int error, fd;
528
David Howells0a370e52008-02-07 00:15:50 -0800529 inode = hostfs_iget(dir->i_sb);
530 if (IS_ERR(inode)) {
531 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700532 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400536 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700537 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 goto out_put;
539
540 fd = file_create(name,
541 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
542 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
543 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400544 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400546 else
Al Viro5e2df282010-06-06 19:38:18 -0400547 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Al Viroe9193052010-06-06 23:16:34 -0400549 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700550 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 goto out_put;
552
553 HOSTFS_I(inode)->fd = fd;
554 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
555 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700556 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
558 out_put:
559 iput(inode);
560 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700561 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
563
564struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700565 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
567 struct inode *inode;
568 char *name;
569 int err;
570
David Howells0a370e52008-02-07 00:15:50 -0800571 inode = hostfs_iget(ino->i_sb);
572 if (IS_ERR(inode)) {
573 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400578 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700579 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 goto out_put;
581
582 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400583
Al Viroe9193052010-06-06 23:16:34 -0400584 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700585 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 iput(inode);
587 inode = NULL;
588 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700589 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 goto out_put;
591
592 d_add(dentry, inode);
593 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700594 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 out_put:
597 iput(inode);
598 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700599 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600}
601
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
603{
Jeff Dikef1adc052007-05-08 00:23:18 -0700604 char *from_name, *to_name;
605 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Al Viroc5322222010-06-06 20:42:10 -0400607 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700608 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400609 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700610 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400611 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700612 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700614 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400615 __putname(from_name);
616 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700617 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618}
619
620int hostfs_unlink(struct inode *ino, struct dentry *dentry)
621{
622 char *file;
623 int err;
624
Al Viroc5322222010-06-06 20:42:10 -0400625 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700626 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700627 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700628 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400631 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700632 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633}
634
635int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
636{
637 char *file;
638 int err;
639
Al Viroc5322222010-06-06 20:42:10 -0400640 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700641 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400643 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700644 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645}
646
647int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
648{
649 char *file;
650 int err;
651
Al Viroc5322222010-06-06 20:42:10 -0400652 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700653 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400655 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700656 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657}
658
659int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
660{
661 char *file;
662 int err;
663
Al Viroc5322222010-06-06 20:42:10 -0400664 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700665 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400667 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700668 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669}
670
671int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
672{
673 struct inode *inode;
674 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800675 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
David Howells0a370e52008-02-07 00:15:50 -0800677 inode = hostfs_iget(dir->i_sb);
678 if (IS_ERR(inode)) {
679 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400684 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700685 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 goto out_put;
687
688 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800689 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400690 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 goto out_free;
692
693 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400694 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400695 if (err)
696 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700697 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 goto out_put;
699
700 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700701 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400704 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 out_put:
706 iput(inode);
707 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700708 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
710
711int hostfs_rename(struct inode *from_ino, struct dentry *from,
712 struct inode *to_ino, struct dentry *to)
713{
714 char *from_name, *to_name;
715 int err;
716
Al Viroc5322222010-06-06 20:42:10 -0400717 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700718 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400719 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400720 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700721 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 }
723 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400724 __putname(from_name);
725 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700726 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727}
728
Al Viroe6305c42008-07-15 21:03:57 -0400729int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
731 char *name;
732 int r = 0, w = 0, x = 0, err;
733
734 if (desired & MAY_READ) r = 1;
735 if (desired & MAY_WRITE) w = 1;
736 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400737 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700738 if (name == NULL)
739 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700742 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 err = 0;
744 else
745 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400746 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700747 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 err = generic_permission(ino, desired, NULL);
749 return err;
750}
751
752int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
753{
Christoph Hellwig10257742010-06-04 11:30:02 +0200754 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 struct hostfs_iattr attrs;
756 char *name;
757 int err;
758
Christoph Hellwig10257742010-06-04 11:30:02 +0200759 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700760
Christoph Hellwig10257742010-06-04 11:30:02 +0200761 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if (err)
763 return err;
764
Jeff Dike84b3db02007-10-16 01:27:13 -0700765 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 attr->ia_valid &= ~ATTR_SIZE;
767
768 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700769 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 attrs.ia_valid |= HOSTFS_ATTR_MODE;
771 attrs.ia_mode = attr->ia_mode;
772 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700773 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 attrs.ia_valid |= HOSTFS_ATTR_UID;
775 attrs.ia_uid = attr->ia_uid;
776 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700777 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 attrs.ia_valid |= HOSTFS_ATTR_GID;
779 attrs.ia_gid = attr->ia_gid;
780 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700781 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
783 attrs.ia_size = attr->ia_size;
784 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700785 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
787 attrs.ia_atime = attr->ia_atime;
788 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700789 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
791 attrs.ia_mtime = attr->ia_mtime;
792 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700793 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
795 attrs.ia_ctime = attr->ia_ctime;
796 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700797 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
799 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700800 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
802 }
Al Viroc5322222010-06-06 20:42:10 -0400803 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700804 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700805 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700806 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400807 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700808 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700809 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Christoph Hellwig10257742010-06-04 11:30:02 +0200811 if ((attr->ia_valid & ATTR_SIZE) &&
812 attr->ia_size != i_size_read(inode)) {
813 int error;
814
815 error = vmtruncate(inode, attr->ia_size);
816 if (err)
817 return err;
818 }
819
820 setattr_copy(inode, attr);
821 mark_inode_dirty(inode);
822 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823}
824
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800825static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 .create = hostfs_create,
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
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800838static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 .create = hostfs_create,
840 .lookup = hostfs_lookup,
841 .link = hostfs_link,
842 .unlink = hostfs_unlink,
843 .symlink = hostfs_symlink,
844 .mkdir = hostfs_mkdir,
845 .rmdir = hostfs_rmdir,
846 .mknod = hostfs_mknod,
847 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 .permission = hostfs_permission,
849 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850};
851
Al Virod0352d32010-06-06 21:51:16 -0400852static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853{
Al Virod0352d32010-06-06 21:51:16 -0400854 char *link = __getname();
855 if (link) {
856 char *path = dentry_name(dentry);
857 int err = -ENOMEM;
858 if (path) {
859 int err = hostfs_do_readlink(path, link, PATH_MAX);
860 if (err == PATH_MAX)
861 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400862 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400863 }
864 if (err < 0) {
865 __putname(link);
866 link = ERR_PTR(err);
867 }
868 } else {
869 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
Al Virod0352d32010-06-06 21:51:16 -0400871
872 nd_set_link(nd, link);
873 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874}
875
Al Virod0352d32010-06-06 21:51:16 -0400876static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
877{
878 char *s = nd_get_link(nd);
879 if (!IS_ERR(s))
880 __putname(s);
881}
882
883static const struct inode_operations hostfs_link_iops = {
884 .readlink = generic_readlink,
885 .follow_link = hostfs_follow_link,
886 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887};
888
889static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
890{
891 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700892 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 int err;
894
895 sb->s_blocksize = 1024;
896 sb->s_blocksize_bits = 10;
897 sb->s_magic = HOSTFS_SUPER_MAGIC;
898 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700899 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800901 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700902 if (req_root == NULL)
903 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
905 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400906 sb->s_fs_info = host_root_path =
907 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700908 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 goto out;
910
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700911 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
Al Viro52b209f2010-06-06 18:43:19 -0400913 root_inode = new_inode(sb);
914 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400915 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Al Viro4754b822010-06-06 20:33:12 -0400917 err = read_name(root_inode, host_root_path);
918 if (err)
919 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400920
Al Viro4754b822010-06-06 20:33:12 -0400921 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400922 char *name = follow_link(host_root_path);
923 if (IS_ERR(name))
924 err = PTR_ERR(name);
925 else
926 err = read_name(root_inode, name);
927 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400928 if (err)
929 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 err = -ENOMEM;
933 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700934 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 goto out_put;
936
Jeff Dikef1adc052007-05-08 00:23:18 -0700937 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Jeff Dikef1adc052007-05-08 00:23:18 -0700939out_put:
940 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700941out:
942 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943}
944
David Howells454e2392006-06-23 02:02:57 -0700945static int hostfs_read_sb(struct file_system_type *type,
946 int flags, const char *dev_name,
947 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
David Howells454e2392006-06-23 02:02:57 -0700949 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950}
951
Al Viro601d2c32010-06-06 17:53:01 -0400952static void hostfs_kill_sb(struct super_block *s)
953{
954 kill_anon_super(s);
955 kfree(s->s_fs_info);
956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958static struct file_system_type hostfs_type = {
959 .owner = THIS_MODULE,
960 .name = "hostfs",
961 .get_sb = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400962 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 .fs_flags = 0,
964};
965
966static int __init init_hostfs(void)
967{
Jeff Dikef1adc052007-05-08 00:23:18 -0700968 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969}
970
971static void __exit exit_hostfs(void)
972{
973 unregister_filesystem(&hostfs_type);
974}
975
976module_init(init_hostfs)
977module_exit(exit_hostfs)
978MODULE_LICENSE("GPL");