blob: 10bb71b1548bd6d629b478f82c2af8e40ddb8383 [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 Viroc5322222010-06-06 20:42:10 -040093static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
95 struct dentry *parent;
96 char *root, *name;
97 int len;
98
99 len = 0;
100 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700101 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 len += parent->d_name.len + 1;
103 parent = parent->d_parent;
104 }
105
Al Viro601d2c32010-06-06 17:53:01 -0400106 root = parent->d_sb->s_fs_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 len += strlen(root);
Al Viroc5322222010-06-06 20:42:10 -0400108 name = kmalloc(len + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700109 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700110 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112 name[len] = '\0';
113 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700114 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 len -= parent->d_name.len + 1;
116 name[len] = '/';
117 strncpy(&name[len + 1], parent->d_name.name,
118 parent->d_name.len);
119 parent = parent->d_parent;
120 }
121 strncpy(name, root, strlen(root));
Jeff Dikef1adc052007-05-08 00:23:18 -0700122 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123}
124
Al Viroc5322222010-06-06 20:42:10 -0400125static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126{
127 struct dentry *dentry;
128
129 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
Al Viroc5322222010-06-06 20:42:10 -0400130 return dentry_name(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133static char *follow_link(char *link)
134{
135 int len, n;
136 char *name, *resolved, *end;
137
138 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700139 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 n = -ENOMEM;
141 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700142 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 goto out;
144
WANG Congea7e7432008-11-19 15:36:46 -0800145 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700146 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 break;
148 len *= 2;
149 kfree(name);
150 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700151 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 goto out_free;
153
Jeff Dike84b3db02007-10-16 01:27:13 -0700154 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700155 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700158 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700159 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161 *(end + 1) = '\0';
162 len = strlen(link) + strlen(name) + 1;
163
164 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700165 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 n = -ENOMEM;
167 goto out_free;
168 }
169
170 sprintf(resolved, "%s%s", link, name);
171 kfree(name);
172 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700173 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175 out_free:
176 kfree(name);
177 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700178 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
David Howells0a370e52008-02-07 00:15:50 -0800181static struct inode *hostfs_iget(struct super_block *sb)
182{
Al Viro52b209f2010-06-06 18:43:19 -0400183 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800184 if (!inode)
185 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800186 return inode;
187}
188
David Howells726c3342006-06-23 02:02:58 -0700189int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
Jeff Dike84b3db02007-10-16 01:27:13 -0700191 /*
192 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 * struct statfs still has 32-bit versions for most of these fields,
194 * so we convert them here
195 */
196 int err;
197 long long f_blocks;
198 long long f_bfree;
199 long long f_bavail;
200 long long f_files;
201 long long f_ffree;
202
Al Viro601d2c32010-06-06 17:53:01 -0400203 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
205 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
206 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700207 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700208 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 sf->f_blocks = f_blocks;
210 sf->f_bfree = f_bfree;
211 sf->f_bavail = f_bavail;
212 sf->f_files = f_files;
213 sf->f_ffree = f_ffree;
214 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700215 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
218static struct inode *hostfs_alloc_inode(struct super_block *sb)
219{
220 struct hostfs_inode_info *hi;
221
Al Viro601d2c32010-06-06 17:53:01 -0400222 hi = kzalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700223 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700224 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400225 hi->fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700227 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228}
229
Al Viroe971a6d2010-06-06 15:16:17 -0400230static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Mark Fashehfef26652005-09-09 13:01:31 -0700232 truncate_inode_pages(&inode->i_data, 0);
Al Viroe971a6d2010-06-06 15:16:17 -0400233 end_writeback(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700234 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 close_file(&HOSTFS_I(inode)->fd);
236 HOSTFS_I(inode)->fd = -1;
237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
239
240static void hostfs_destroy_inode(struct inode *inode)
241{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 kfree(HOSTFS_I(inode));
243}
244
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800245static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
246{
Al Viro601d2c32010-06-06 17:53:01 -0400247 const char *root_path = vfs->mnt_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800248 size_t offset = strlen(root_ino) + 1;
249
250 if (strlen(root_path) > offset)
251 seq_printf(seq, ",%s", root_path + offset);
252
253 return 0;
254}
255
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800256static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400259 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800261 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262};
263
264int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
265{
266 void *dir;
267 char *name;
268 unsigned long long next, ino;
269 int error, len;
270
Al Viroc5322222010-06-06 20:42:10 -0400271 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700272 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700273 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 dir = open_dir(name, &error);
275 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700276 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700277 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700279 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 error = (*filldir)(ent, name, len, file->f_pos,
281 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700282 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 file->f_pos = next;
284 }
285 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700286 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287}
288
289int hostfs_file_open(struct inode *ino, struct file *file)
290{
291 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400292 fmode_t mode = 0;
293 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700296 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700297 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Jeff Dike84b3db02007-10-16 01:27:13 -0700299 /*
300 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 * so this resets things and reopens the file with the new access.
302 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700303 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 close_file(&HOSTFS_I(ino)->fd);
305 HOSTFS_I(ino)->fd = -1;
306 }
307
308 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700309 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700311 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700313 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 r = 1;
315
Al Viroc5322222010-06-06 20:42:10 -0400316 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700317 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700318 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320 fd = open_file(name, r, w, append);
321 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700322 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700323 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 FILE_HOSTFS_I(file)->fd = fd;
325
Jeff Dikef1adc052007-05-08 00:23:18 -0700326 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200329int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200331 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800334static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700336 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200337 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 .aio_read = generic_file_aio_read,
339 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700340 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 .mmap = generic_file_mmap,
342 .open = hostfs_file_open,
343 .release = NULL,
344 .fsync = hostfs_fsync,
345};
346
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800347static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 .llseek = generic_file_llseek,
349 .readdir = hostfs_readdir,
350 .read = generic_read_dir,
351};
352
353int hostfs_writepage(struct page *page, struct writeback_control *wbc)
354{
355 struct address_space *mapping = page->mapping;
356 struct inode *inode = mapping->host;
357 char *buffer;
358 unsigned long long base;
359 int count = PAGE_CACHE_SIZE;
360 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
361 int err;
362
363 if (page->index >= end_index)
364 count = inode->i_size & (PAGE_CACHE_SIZE-1);
365
366 buffer = kmap(page);
367 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
368
369 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700370 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 ClearPageUptodate(page);
372 goto out;
373 }
374
375 if (base > inode->i_size)
376 inode->i_size = base;
377
378 if (PageError(page))
379 ClearPageError(page);
380 err = 0;
381
382 out:
383 kunmap(page);
384
385 unlock_page(page);
386 return err;
387}
388
389int hostfs_readpage(struct file *file, struct page *page)
390{
391 char *buffer;
392 long long start;
393 int err = 0;
394
395 start = (long long) page->index << PAGE_CACHE_SHIFT;
396 buffer = kmap(page);
397 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
398 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700399 if (err < 0)
400 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
403
404 flush_dcache_page(page);
405 SetPageUptodate(page);
406 if (PageError(page)) ClearPageError(page);
407 err = 0;
408 out:
409 kunmap(page);
410 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700411 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
Nick Pigginae361ff2007-10-16 01:25:17 -0700414int hostfs_write_begin(struct file *file, struct address_space *mapping,
415 loff_t pos, unsigned len, unsigned flags,
416 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
Nick Pigginae361ff2007-10-16 01:25:17 -0700418 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Nick Piggin54566b22009-01-04 12:00:53 -0800420 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700421 if (!*pagep)
422 return -ENOMEM;
423 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424}
425
Nick Pigginae361ff2007-10-16 01:25:17 -0700426int hostfs_write_end(struct file *file, struct address_space *mapping,
427 loff_t pos, unsigned len, unsigned copied,
428 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700431 void *buffer;
432 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
433 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700436 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700438
439 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
440 SetPageUptodate(page);
441
Jeff Dike84b3db02007-10-16 01:27:13 -0700442 /*
443 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700444 * i_size against the last byte written.
445 */
446 if (err > 0 && (pos > inode->i_size))
447 inode->i_size = pos;
448 unlock_page(page);
449 page_cache_release(page);
450
Jeff Dikef1adc052007-05-08 00:23:18 -0700451 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452}
453
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700454static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 .writepage = hostfs_writepage,
456 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700457 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700458 .write_begin = hostfs_write_begin,
459 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460};
461
Al Viro4754b822010-06-06 20:33:12 -0400462static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
Al Viro4754b822010-06-06 20:33:12 -0400464 dev_t rdev;
465 struct hostfs_stat st;
466 int err = stat_file(name, &st, -1);
467 if (err)
468 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Al Viro5e2df282010-06-06 19:38:18 -0400470 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400471 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Al Viro4754b822010-06-06 20:33:12 -0400473 switch (st.mode & S_IFMT) {
474 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400475 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400476 break;
477 case S_IFDIR:
478 ino->i_op = &hostfs_dir_iops;
479 ino->i_fop = &hostfs_dir_fops;
480 break;
481 case S_IFCHR:
482 case S_IFBLK:
483 case S_IFIFO:
484 case S_IFSOCK:
485 init_special_inode(ino, st.mode & S_IFMT, rdev);
486 ino->i_op = &hostfs_iops;
487 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Al Viro4754b822010-06-06 20:33:12 -0400489 default:
490 ino->i_op = &hostfs_iops;
491 ino->i_fop = &hostfs_file_fops;
492 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 }
Al Viro4754b822010-06-06 20:33:12 -0400494
495 ino->i_ino = st.ino;
496 ino->i_mode = st.mode;
497 ino->i_nlink = st.nlink;
498 ino->i_uid = st.uid;
499 ino->i_gid = st.gid;
500 ino->i_atime = st.atime;
501 ino->i_mtime = st.mtime;
502 ino->i_ctime = st.ctime;
503 ino->i_size = st.size;
504 ino->i_blocks = st.blocks;
505 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
508int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700509 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 struct inode *inode;
512 char *name;
513 int error, fd;
514
David Howells0a370e52008-02-07 00:15:50 -0800515 inode = hostfs_iget(dir->i_sb);
516 if (IS_ERR(inode)) {
517 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700518 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400522 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700523 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 goto out_put;
525
526 fd = file_create(name,
527 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
528 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
529 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400530 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400532 else
Al Viro5e2df282010-06-06 19:38:18 -0400533 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
535 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700536 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 goto out_put;
538
539 HOSTFS_I(inode)->fd = fd;
540 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
541 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700542 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 out_put:
545 iput(inode);
546 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700547 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548}
549
550struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700551 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
553 struct inode *inode;
554 char *name;
555 int err;
556
David Howells0a370e52008-02-07 00:15:50 -0800557 inode = hostfs_iget(ino->i_sb);
558 if (IS_ERR(inode)) {
559 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400564 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700565 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 goto out_put;
567
568 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700571 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 iput(inode);
573 inode = NULL;
574 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700575 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 goto out_put;
577
578 d_add(dentry, inode);
579 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700580 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
582 out_put:
583 iput(inode);
584 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700585 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
589{
Jeff Dikef1adc052007-05-08 00:23:18 -0700590 char *from_name, *to_name;
591 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Al Viroc5322222010-06-06 20:42:10 -0400593 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700594 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400595 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700596 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700598 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700600 err = link_file(to_name, from_name);
601 kfree(from_name);
602 kfree(to_name);
603 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604}
605
606int hostfs_unlink(struct inode *ino, struct dentry *dentry)
607{
608 char *file;
609 int err;
610
Al Viroc5322222010-06-06 20:42:10 -0400611 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700612 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700613 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700614 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 err = unlink_file(file);
617 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700618 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619}
620
621int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
622{
623 char *file;
624 int err;
625
Al Viroc5322222010-06-06 20:42:10 -0400626 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700627 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 err = make_symlink(file, to);
629 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700630 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
633int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
634{
635 char *file;
636 int err;
637
Al Viroc5322222010-06-06 20:42:10 -0400638 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 err = do_mkdir(file, mode);
641 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700642 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643}
644
645int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
646{
647 char *file;
648 int err;
649
Al Viroc5322222010-06-06 20:42:10 -0400650 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700651 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 err = do_rmdir(file);
653 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700654 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
656
657int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
658{
659 struct inode *inode;
660 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800661 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
David Howells0a370e52008-02-07 00:15:50 -0800663 inode = hostfs_iget(dir->i_sb);
664 if (IS_ERR(inode)) {
665 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400670 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700671 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 goto out_put;
673
674 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800675 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700676 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 goto out_free;
678
679 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400680 if (err)
681 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700683 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 goto out_put;
685
686 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689 out_free:
690 kfree(name);
691 out_put:
692 iput(inode);
693 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700694 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
697int hostfs_rename(struct inode *from_ino, struct dentry *from,
698 struct inode *to_ino, struct dentry *to)
699{
700 char *from_name, *to_name;
701 int err;
702
Al Viroc5322222010-06-06 20:42:10 -0400703 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700704 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400705 if ((to_name = dentry_name(to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700707 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
709 err = rename_file(from_name, to_name);
710 kfree(from_name);
711 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700712 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713}
714
Al Viroe6305c42008-07-15 21:03:57 -0400715int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
717 char *name;
718 int r = 0, w = 0, x = 0, err;
719
720 if (desired & MAY_READ) r = 1;
721 if (desired & MAY_WRITE) w = 1;
722 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400723 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700724 if (name == NULL)
725 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700728 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 err = 0;
730 else
731 err = access_file(name, r, w, x);
732 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700733 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 err = generic_permission(ino, desired, NULL);
735 return err;
736}
737
738int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
739{
Christoph Hellwig10257742010-06-04 11:30:02 +0200740 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 struct hostfs_iattr attrs;
742 char *name;
743 int err;
744
Christoph Hellwig10257742010-06-04 11:30:02 +0200745 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700746
Christoph Hellwig10257742010-06-04 11:30:02 +0200747 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 if (err)
749 return err;
750
Jeff Dike84b3db02007-10-16 01:27:13 -0700751 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 attr->ia_valid &= ~ATTR_SIZE;
753
754 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700755 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 attrs.ia_valid |= HOSTFS_ATTR_MODE;
757 attrs.ia_mode = attr->ia_mode;
758 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700759 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 attrs.ia_valid |= HOSTFS_ATTR_UID;
761 attrs.ia_uid = attr->ia_uid;
762 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700763 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 attrs.ia_valid |= HOSTFS_ATTR_GID;
765 attrs.ia_gid = attr->ia_gid;
766 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700767 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
769 attrs.ia_size = attr->ia_size;
770 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700771 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
773 attrs.ia_atime = attr->ia_atime;
774 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700775 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
777 attrs.ia_mtime = attr->ia_mtime;
778 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700779 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
781 attrs.ia_ctime = attr->ia_ctime;
782 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700783 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
785 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700786 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
788 }
Al Viroc5322222010-06-06 20:42:10 -0400789 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700790 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700791 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700792 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700794 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700795 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Christoph Hellwig10257742010-06-04 11:30:02 +0200797 if ((attr->ia_valid & ATTR_SIZE) &&
798 attr->ia_size != i_size_read(inode)) {
799 int error;
800
801 error = vmtruncate(inode, attr->ia_size);
802 if (err)
803 return err;
804 }
805
806 setattr_copy(inode, attr);
807 mark_inode_dirty(inode);
808 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800811static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 .create = hostfs_create,
813 .link = hostfs_link,
814 .unlink = hostfs_unlink,
815 .symlink = hostfs_symlink,
816 .mkdir = hostfs_mkdir,
817 .rmdir = hostfs_rmdir,
818 .mknod = hostfs_mknod,
819 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 .permission = hostfs_permission,
821 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822};
823
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800824static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 .create = hostfs_create,
826 .lookup = hostfs_lookup,
827 .link = hostfs_link,
828 .unlink = hostfs_unlink,
829 .symlink = hostfs_symlink,
830 .mkdir = hostfs_mkdir,
831 .rmdir = hostfs_rmdir,
832 .mknod = hostfs_mknod,
833 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 .permission = hostfs_permission,
835 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836};
837
Al Virod0352d32010-06-06 21:51:16 -0400838static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839{
Al Virod0352d32010-06-06 21:51:16 -0400840 char *link = __getname();
841 if (link) {
842 char *path = dentry_name(dentry);
843 int err = -ENOMEM;
844 if (path) {
845 int err = hostfs_do_readlink(path, link, PATH_MAX);
846 if (err == PATH_MAX)
847 err = -E2BIG;
848 kfree(path);
849 }
850 if (err < 0) {
851 __putname(link);
852 link = ERR_PTR(err);
853 }
854 } else {
855 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 }
Al Virod0352d32010-06-06 21:51:16 -0400857
858 nd_set_link(nd, link);
859 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
Al Virod0352d32010-06-06 21:51:16 -0400862static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
863{
864 char *s = nd_get_link(nd);
865 if (!IS_ERR(s))
866 __putname(s);
867}
868
869static const struct inode_operations hostfs_link_iops = {
870 .readlink = generic_readlink,
871 .follow_link = hostfs_follow_link,
872 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873};
874
875static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
876{
877 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700878 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 int err;
880
881 sb->s_blocksize = 1024;
882 sb->s_blocksize_bits = 10;
883 sb->s_magic = HOSTFS_SUPER_MAGIC;
884 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700885 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800887 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700888 if (req_root == NULL)
889 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400892 sb->s_fs_info = host_root_path =
893 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700894 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 goto out;
896
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700897 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
Al Viro52b209f2010-06-06 18:43:19 -0400899 root_inode = new_inode(sb);
900 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400901 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Al Viro4754b822010-06-06 20:33:12 -0400903 err = read_name(root_inode, host_root_path);
904 if (err)
905 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400906
Al Viro4754b822010-06-06 20:33:12 -0400907 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400908 char *name = follow_link(host_root_path);
909 if (IS_ERR(name))
910 err = PTR_ERR(name);
911 else
912 err = read_name(root_inode, name);
913 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400914 if (err)
915 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 err = -ENOMEM;
919 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700920 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 goto out_put;
922
Jeff Dikef1adc052007-05-08 00:23:18 -0700923 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
Jeff Dikef1adc052007-05-08 00:23:18 -0700925out_put:
926 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700927out:
928 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929}
930
David Howells454e2392006-06-23 02:02:57 -0700931static int hostfs_read_sb(struct file_system_type *type,
932 int flags, const char *dev_name,
933 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{
David Howells454e2392006-06-23 02:02:57 -0700935 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936}
937
Al Viro601d2c32010-06-06 17:53:01 -0400938static void hostfs_kill_sb(struct super_block *s)
939{
940 kill_anon_super(s);
941 kfree(s->s_fs_info);
942}
943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944static struct file_system_type hostfs_type = {
945 .owner = THIS_MODULE,
946 .name = "hostfs",
947 .get_sb = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400948 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 .fs_flags = 0,
950};
951
952static int __init init_hostfs(void)
953{
Jeff Dikef1adc052007-05-08 00:23:18 -0700954 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955}
956
957static void __exit exit_hostfs(void)
958{
959 unregister_filesystem(&hostfs_type);
960}
961
962module_init(init_hostfs)
963module_exit(exit_hostfs)
964MODULE_LICENSE("GPL");