blob: 8130ce93a06a7fd25e9a962eca7bb43a17e3f51a [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 Viro52b209f72010-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
Jeff Dike84b3db02007-10-16 01:27:13 -0700625 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700626 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Al Virof8d7e182010-06-06 23:19:04 -0400628 if ((file = dentry_name(dentry)) == NULL)
629 return -ENOMEM;
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400632 __putname(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
Al Viroc5322222010-06-06 20:42:10 -0400641 if ((file = dentry_name(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);
Al Viroe9193052010-06-06 23:16:34 -0400644 __putname(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
Al Viroc5322222010-06-06 20:42:10 -0400653 if ((file = dentry_name(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);
Al Viroe9193052010-06-06 23:16:34 -0400656 __putname(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
Al Viroc5322222010-06-06 20:42:10 -0400665 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700666 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400668 __putname(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;
Al Viroc5322222010-06-06 20:42:10 -0400685 name = dentry_name(dentry);
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));
Al Viroe9193052010-06-06 23:16:34 -0400691 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 goto out_free;
693
694 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400695 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400696 if (err)
697 goto out_put;
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:
Al Viroe9193052010-06-06 23:16:34 -0400705 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 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
Al Viroc5322222010-06-06 20:42:10 -0400718 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700719 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400720 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400721 __putname(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);
Al Viroe9193052010-06-06 23:16:34 -0400725 __putname(from_name);
726 __putname(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;
Al Viroc5322222010-06-06 20:42:10 -0400738 name = inode_name(ino);
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);
Al Viroe9193052010-06-06 23:16:34 -0400747 __putname(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 }
Al Viroc5322222010-06-06 20:42:10 -0400804 name = dentry_name(dentry);
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);
Al Viroe9193052010-06-06 23:16:34 -0400808 __putname(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
Al Virod0352d32010-06-06 21:51:16 -0400853static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854{
Al Virod0352d32010-06-06 21:51:16 -0400855 char *link = __getname();
856 if (link) {
857 char *path = dentry_name(dentry);
858 int err = -ENOMEM;
859 if (path) {
860 int err = hostfs_do_readlink(path, link, PATH_MAX);
861 if (err == PATH_MAX)
862 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400863 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400864 }
865 if (err < 0) {
866 __putname(link);
867 link = ERR_PTR(err);
868 }
869 } else {
870 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 }
Al Virod0352d32010-06-06 21:51:16 -0400872
873 nd_set_link(nd, link);
874 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875}
876
Al Virod0352d32010-06-06 21:51:16 -0400877static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
878{
879 char *s = nd_get_link(nd);
880 if (!IS_ERR(s))
881 __putname(s);
882}
883
884static const struct inode_operations hostfs_link_iops = {
885 .readlink = generic_readlink,
886 .follow_link = hostfs_follow_link,
887 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888};
889
890static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
891{
892 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700893 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 int err;
895
896 sb->s_blocksize = 1024;
897 sb->s_blocksize_bits = 10;
898 sb->s_magic = HOSTFS_SUPER_MAGIC;
899 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700900 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800902 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700903 if (req_root == NULL)
904 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400907 sb->s_fs_info = host_root_path =
908 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700909 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 goto out;
911
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700912 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Al Viro52b209f72010-06-06 18:43:19 -0400914 root_inode = new_inode(sb);
915 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400916 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Al Viro4754b822010-06-06 20:33:12 -0400918 err = read_name(root_inode, host_root_path);
919 if (err)
920 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400921
Al Viro4754b822010-06-06 20:33:12 -0400922 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400923 char *name = follow_link(host_root_path);
924 if (IS_ERR(name))
925 err = PTR_ERR(name);
926 else
927 err = read_name(root_inode, name);
928 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400929 if (err)
930 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 err = -ENOMEM;
934 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700935 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 goto out_put;
937
Jeff Dikef1adc052007-05-08 00:23:18 -0700938 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Jeff Dikef1adc052007-05-08 00:23:18 -0700940out_put:
941 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700942out:
943 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944}
945
David Howells454e2392006-06-23 02:02:57 -0700946static int hostfs_read_sb(struct file_system_type *type,
947 int flags, const char *dev_name,
948 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949{
David Howells454e2392006-06-23 02:02:57 -0700950 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951}
952
Al Viro601d2c32010-06-06 17:53:01 -0400953static void hostfs_kill_sb(struct super_block *s)
954{
955 kill_anon_super(s);
956 kfree(s->s_fs_info);
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959static struct file_system_type hostfs_type = {
960 .owner = THIS_MODULE,
961 .name = "hostfs",
962 .get_sb = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400963 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 .fs_flags = 0,
965};
966
967static int __init init_hostfs(void)
968{
Jeff Dikef1adc052007-05-08 00:23:18 -0700969 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970}
971
972static void __exit exit_hostfs(void)
973{
974 unregister_filesystem(&hostfs_type);
975}
976
977module_init(init_hostfs)
978module_exit(exit_hostfs)
979MODULE_LICENSE("GPL");