blob: 25d79298a98e89638ff214c9bd87145e809091c0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jeff Dikef1adc052007-05-08 00:23:18 -07002 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 *
5 * Ported the filesystem routines to 2.5.
6 * 2003-02-10 Petr Baudis <pasky@ucw.cz>
7 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/module.h>
Jeff Dike84b3db02007-10-16 01:27:13 -070011#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/statfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -080015#include <linux/seq_file.h>
Jiri Kosina6966a972008-02-09 00:10:14 -080016#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "hostfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "init.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070019#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
21struct hostfs_inode_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 int fd;
Al Viroaeb5d722008-09-02 15:28:45 -040023 fmode_t mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 struct inode vfs_inode;
25};
26
27static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
28{
Jeff Dikef1adc052007-05-08 00:23:18 -070029 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070030}
31
Josef Sipek680b0da2006-12-08 02:37:05 -080032#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Al Viroe16404e2009-02-20 05:55:13 +000034static int hostfs_d_delete(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035{
Jeff Dikef1adc052007-05-08 00:23:18 -070036 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070037}
38
Al Viroe16404e2009-02-20 05:55:13 +000039static const struct dentry_operations hostfs_dentry_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 .d_delete = hostfs_d_delete,
41};
42
43/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080044static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070045static int append = 0;
46
47#define HOSTFS_SUPER_MAGIC 0x00c0ffee
48
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080049static const struct inode_operations hostfs_iops;
50static const struct inode_operations hostfs_dir_iops;
Christoph Hellwigf5e54d62006-06-28 04:26:44 -070051static const struct address_space_operations hostfs_link_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#ifndef MODULE
54static int __init hostfs_args(char *options, int *add)
55{
56 char *ptr;
57
58 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070059 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070061 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 root_ino = options;
63
64 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070065 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070067 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070069 if (*options != '\0') {
70 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 append = 1;
72 else printf("hostfs_args - unsupported option - %s\n",
73 options);
74 }
75 options = ptr;
76 }
Jeff Dikef1adc052007-05-08 00:23:18 -070077 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
80__uml_setup("hostfs=", hostfs_args,
81"hostfs=<root dir>,<flags>,...\n"
82" This is used to set hostfs parameters. The root directory argument\n"
83" is used to confine all hostfs mounts to within the specified directory\n"
84" tree on the host. If this isn't specified, then a user inside UML can\n"
85" mount anything on the host that's accessible to the user that's running\n"
86" it.\n"
87" The only flag currently supported is 'append', which specifies that all\n"
88" files opened by hostfs will be opened in append mode.\n\n"
89);
90#endif
91
92static char *dentry_name(struct dentry *dentry, int extra)
93{
94 struct dentry *parent;
95 char *root, *name;
96 int len;
97
98 len = 0;
99 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700100 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 len += parent->d_name.len + 1;
102 parent = parent->d_parent;
103 }
104
Al Viro601d2c32010-06-06 17:53:01 -0400105 root = parent->d_sb->s_fs_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 len += strlen(root);
107 name = kmalloc(len + extra + 1, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700108 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700109 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
111 name[len] = '\0';
112 parent = dentry;
Jeff Dike84b3db02007-10-16 01:27:13 -0700113 while (parent->d_parent != parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 len -= parent->d_name.len + 1;
115 name[len] = '/';
116 strncpy(&name[len + 1], parent->d_name.name,
117 parent->d_name.len);
118 parent = parent->d_parent;
119 }
120 strncpy(name, root, strlen(root));
Jeff Dikef1adc052007-05-08 00:23:18 -0700121 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
124static char *inode_name(struct inode *ino, int extra)
125{
126 struct dentry *dentry;
127
128 dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
Jeff Dikef1adc052007-05-08 00:23:18 -0700129 return dentry_name(dentry, extra);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130}
131
132static int read_name(struct inode *ino, char *name)
133{
Jeff Dike84b3db02007-10-16 01:27:13 -0700134 /*
135 * The non-int inode fields are copied into ints by stat_file and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 * then copied into the inode because passing the actual pointers
137 * in and having them treated as int * breaks on big-endian machines
138 */
139 int err;
140 int i_mode, i_nlink, i_blksize;
141 unsigned long long i_size;
142 unsigned long long i_ino;
143 unsigned long long i_blocks;
144
145 err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
146 &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700147 &ino->i_ctime, &i_blksize, &i_blocks, -1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700148 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700149 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 ino->i_ino = i_ino;
152 ino->i_mode = i_mode;
153 ino->i_nlink = i_nlink;
154 ino->i_size = i_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 ino->i_blocks = i_blocks;
Jeff Dikef1adc052007-05-08 00:23:18 -0700156 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157}
158
159static char *follow_link(char *link)
160{
161 int len, n;
162 char *name, *resolved, *end;
163
164 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700165 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 n = -ENOMEM;
167 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700168 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 goto out;
170
WANG Congea7e7432008-11-19 15:36:46 -0800171 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700172 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 break;
174 len *= 2;
175 kfree(name);
176 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700177 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 goto out_free;
179
Jeff Dike84b3db02007-10-16 01:27:13 -0700180 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700181 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700184 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700185 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
187 *(end + 1) = '\0';
188 len = strlen(link) + strlen(name) + 1;
189
190 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700191 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 n = -ENOMEM;
193 goto out_free;
194 }
195
196 sprintf(resolved, "%s%s", link, name);
197 kfree(name);
198 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700199 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201 out_free:
202 kfree(name);
203 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700204 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
David Howells0a370e52008-02-07 00:15:50 -0800207static struct inode *hostfs_iget(struct super_block *sb)
208{
Al Viro52b209f2010-06-06 18:43:19 -0400209 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800210 if (!inode)
211 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800212 return inode;
213}
214
David Howells726c3342006-06-23 02:02:58 -0700215int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
Jeff Dike84b3db02007-10-16 01:27:13 -0700217 /*
218 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 * struct statfs still has 32-bit versions for most of these fields,
220 * so we convert them here
221 */
222 int err;
223 long long f_blocks;
224 long long f_bfree;
225 long long f_bavail;
226 long long f_files;
227 long long f_ffree;
228
Al Viro601d2c32010-06-06 17:53:01 -0400229 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
231 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
232 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700233 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700234 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 sf->f_blocks = f_blocks;
236 sf->f_bfree = f_bfree;
237 sf->f_bavail = f_bavail;
238 sf->f_files = f_files;
239 sf->f_ffree = f_ffree;
240 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700241 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
244static struct inode *hostfs_alloc_inode(struct super_block *sb)
245{
246 struct hostfs_inode_info *hi;
247
Al Viro601d2c32010-06-06 17:53:01 -0400248 hi = kzalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700249 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700250 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400251 hi->fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700253 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254}
255
Al Viroe971a6d2010-06-06 15:16:17 -0400256static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
Mark Fashehfef26652005-09-09 13:01:31 -0700258 truncate_inode_pages(&inode->i_data, 0);
Al Viroe971a6d2010-06-06 15:16:17 -0400259 end_writeback(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700260 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 close_file(&HOSTFS_I(inode)->fd);
262 HOSTFS_I(inode)->fd = -1;
263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265
266static void hostfs_destroy_inode(struct inode *inode)
267{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 kfree(HOSTFS_I(inode));
269}
270
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800271static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
272{
Al Viro601d2c32010-06-06 17:53:01 -0400273 const char *root_path = vfs->mnt_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800274 size_t offset = strlen(root_ino) + 1;
275
276 if (strlen(root_path) > offset)
277 seq_printf(seq, ",%s", root_path + offset);
278
279 return 0;
280}
281
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800282static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400285 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800287 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288};
289
290int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
291{
292 void *dir;
293 char *name;
294 unsigned long long next, ino;
295 int error, len;
296
Josef Sipek680b0da2006-12-08 02:37:05 -0800297 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700298 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700299 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 dir = open_dir(name, &error);
301 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700302 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700303 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700305 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 error = (*filldir)(ent, name, len, file->f_pos,
307 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700308 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 file->f_pos = next;
310 }
311 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700312 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313}
314
315int hostfs_file_open(struct inode *ino, struct file *file)
316{
317 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400318 fmode_t mode = 0;
319 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700322 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700323 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Jeff Dike84b3db02007-10-16 01:27:13 -0700325 /*
326 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 * so this resets things and reopens the file with the new access.
328 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700329 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 close_file(&HOSTFS_I(ino)->fd);
331 HOSTFS_I(ino)->fd = -1;
332 }
333
334 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700335 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700337 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700339 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 r = 1;
341
Josef Sipek680b0da2006-12-08 02:37:05 -0800342 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700343 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700344 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346 fd = open_file(name, r, w, append);
347 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700348 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700349 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 FILE_HOSTFS_I(file)->fd = fd;
351
Jeff Dikef1adc052007-05-08 00:23:18 -0700352 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353}
354
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200355int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200357 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358}
359
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800360static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700362 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200363 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 .aio_read = generic_file_aio_read,
365 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700366 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 .mmap = generic_file_mmap,
368 .open = hostfs_file_open,
369 .release = NULL,
370 .fsync = hostfs_fsync,
371};
372
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800373static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 .llseek = generic_file_llseek,
375 .readdir = hostfs_readdir,
376 .read = generic_read_dir,
377};
378
379int hostfs_writepage(struct page *page, struct writeback_control *wbc)
380{
381 struct address_space *mapping = page->mapping;
382 struct inode *inode = mapping->host;
383 char *buffer;
384 unsigned long long base;
385 int count = PAGE_CACHE_SIZE;
386 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
387 int err;
388
389 if (page->index >= end_index)
390 count = inode->i_size & (PAGE_CACHE_SIZE-1);
391
392 buffer = kmap(page);
393 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
394
395 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700396 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 ClearPageUptodate(page);
398 goto out;
399 }
400
401 if (base > inode->i_size)
402 inode->i_size = base;
403
404 if (PageError(page))
405 ClearPageError(page);
406 err = 0;
407
408 out:
409 kunmap(page);
410
411 unlock_page(page);
412 return err;
413}
414
415int hostfs_readpage(struct file *file, struct page *page)
416{
417 char *buffer;
418 long long start;
419 int err = 0;
420
421 start = (long long) page->index << PAGE_CACHE_SHIFT;
422 buffer = kmap(page);
423 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
424 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700425 if (err < 0)
426 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
429
430 flush_dcache_page(page);
431 SetPageUptodate(page);
432 if (PageError(page)) ClearPageError(page);
433 err = 0;
434 out:
435 kunmap(page);
436 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700437 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438}
439
Nick Pigginae361ff2007-10-16 01:25:17 -0700440int hostfs_write_begin(struct file *file, struct address_space *mapping,
441 loff_t pos, unsigned len, unsigned flags,
442 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
Nick Pigginae361ff2007-10-16 01:25:17 -0700444 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Nick Piggin54566b22009-01-04 12:00:53 -0800446 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700447 if (!*pagep)
448 return -ENOMEM;
449 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450}
451
Nick Pigginae361ff2007-10-16 01:25:17 -0700452int hostfs_write_end(struct file *file, struct address_space *mapping,
453 loff_t pos, unsigned len, unsigned copied,
454 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700457 void *buffer;
458 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
459 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700462 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700464
465 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
466 SetPageUptodate(page);
467
Jeff Dike84b3db02007-10-16 01:27:13 -0700468 /*
469 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700470 * i_size against the last byte written.
471 */
472 if (err > 0 && (pos > inode->i_size))
473 inode->i_size = pos;
474 unlock_page(page);
475 page_cache_release(page);
476
Jeff Dikef1adc052007-05-08 00:23:18 -0700477 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478}
479
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700480static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 .writepage = hostfs_writepage,
482 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700483 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700484 .write_begin = hostfs_write_begin,
485 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486};
487
488static int init_inode(struct inode *inode, struct dentry *dentry)
489{
490 char *name;
491 int type, err = -ENOMEM;
492 int maj, min;
493 dev_t rdev = 0;
494
Jeff Dike84b3db02007-10-16 01:27:13 -0700495 if (dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700497 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 goto out;
499 type = file_type(name, &maj, &min);
Jeff Dike84b3db02007-10-16 01:27:13 -0700500 /* Reencode maj and min with the kernel encoding.*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 rdev = MKDEV(maj, min);
502 kfree(name);
503 }
504 else type = OS_TYPE_DIR;
505
506 err = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700507 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700509 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 inode->i_op = &hostfs_dir_iops;
511 else inode->i_op = &hostfs_iops;
512
Jeff Dike84b3db02007-10-16 01:27:13 -0700513 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 else inode->i_fop = &hostfs_file_fops;
515
Jeff Dike84b3db02007-10-16 01:27:13 -0700516 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 inode->i_mapping->a_ops = &hostfs_link_aops;
518 else inode->i_mapping->a_ops = &hostfs_aops;
519
520 switch (type) {
521 case OS_TYPE_CHARDEV:
522 init_special_inode(inode, S_IFCHR, rdev);
523 break;
524 case OS_TYPE_BLOCKDEV:
525 init_special_inode(inode, S_IFBLK, rdev);
526 break;
527 case OS_TYPE_FIFO:
528 init_special_inode(inode, S_IFIFO, 0);
529 break;
530 case OS_TYPE_SOCK:
531 init_special_inode(inode, S_IFSOCK, 0);
532 break;
533 }
534 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700535 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536}
537
538int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700539 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 struct inode *inode;
542 char *name;
543 int error, fd;
544
David Howells0a370e52008-02-07 00:15:50 -0800545 inode = hostfs_iget(dir->i_sb);
546 if (IS_ERR(inode)) {
547 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700548 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 error = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700552 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 goto out_put;
554
555 error = -ENOMEM;
556 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700557 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 goto out_put;
559
560 fd = file_create(name,
561 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
562 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
563 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Jeff Dike84b3db02007-10-16 01:27:13 -0700564 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 error = fd;
566 else error = read_name(inode, name);
567
568 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700569 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 goto out_put;
571
572 HOSTFS_I(inode)->fd = fd;
573 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
574 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700575 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
577 out_put:
578 iput(inode);
579 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700580 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581}
582
583struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700584 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 struct inode *inode;
587 char *name;
588 int err;
589
David Howells0a370e52008-02-07 00:15:50 -0800590 inode = hostfs_iget(ino->i_sb);
591 if (IS_ERR(inode)) {
592 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700597 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 goto out_put;
599
600 err = -ENOMEM;
601 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700602 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 goto out_put;
604
605 err = read_name(inode, name);
606 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700607 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 iput(inode);
609 inode = NULL;
610 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700611 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto out_put;
613
614 d_add(dentry, inode);
615 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700616 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 out_put:
619 iput(inode);
620 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700621 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622}
623
624static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
625{
Jeff Dikef1adc052007-05-08 00:23:18 -0700626 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 int len;
628
629 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700630 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700631 return NULL;
632 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700634 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700636 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637}
638
639int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
640{
Jeff Dikef1adc052007-05-08 00:23:18 -0700641 char *from_name, *to_name;
642 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Jeff Dike84b3db02007-10-16 01:27:13 -0700644 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700645 return -ENOMEM;
646 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700647 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700651 err = link_file(to_name, from_name);
652 kfree(from_name);
653 kfree(to_name);
654 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
656
657int hostfs_unlink(struct inode *ino, struct dentry *dentry)
658{
659 char *file;
660 int err;
661
Jeff Dike84b3db02007-10-16 01:27:13 -0700662 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700663 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700664 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700665 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 err = unlink_file(file);
668 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700669 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670}
671
672int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
673{
674 char *file;
675 int err;
676
Jeff Dike84b3db02007-10-16 01:27:13 -0700677 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700678 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 err = make_symlink(file, to);
680 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700681 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682}
683
684int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
685{
686 char *file;
687 int err;
688
Jeff Dike84b3db02007-10-16 01:27:13 -0700689 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 err = do_mkdir(file, mode);
692 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700693 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694}
695
696int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
697{
698 char *file;
699 int err;
700
Jeff Dike84b3db02007-10-16 01:27:13 -0700701 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700702 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 err = do_rmdir(file);
704 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700705 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706}
707
708int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
709{
710 struct inode *inode;
711 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800712 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
David Howells0a370e52008-02-07 00:15:50 -0800714 inode = hostfs_iget(dir->i_sb);
715 if (IS_ERR(inode)) {
716 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700721 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 goto out_put;
723
724 err = -ENOMEM;
725 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700726 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 goto out_put;
728
729 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800730 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700731 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 goto out_free;
733
734 err = read_name(inode, name);
735 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700736 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 goto out_put;
738
739 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700740 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 out_free:
743 kfree(name);
744 out_put:
745 iput(inode);
746 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700747 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748}
749
750int hostfs_rename(struct inode *from_ino, struct dentry *from,
751 struct inode *to_ino, struct dentry *to)
752{
753 char *from_name, *to_name;
754 int err;
755
Jeff Dike84b3db02007-10-16 01:27:13 -0700756 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700757 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700758 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700760 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 }
762 err = rename_file(from_name, to_name);
763 kfree(from_name);
764 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700765 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766}
767
Al Viroe6305c42008-07-15 21:03:57 -0400768int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
770 char *name;
771 int r = 0, w = 0, x = 0, err;
772
773 if (desired & MAY_READ) r = 1;
774 if (desired & MAY_WRITE) w = 1;
775 if (desired & MAY_EXEC) x = 1;
776 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700777 if (name == NULL)
778 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700781 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 err = 0;
783 else
784 err = access_file(name, r, w, x);
785 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700786 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 err = generic_permission(ino, desired, NULL);
788 return err;
789}
790
791int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
792{
Christoph Hellwig10257742010-06-04 11:30:02 +0200793 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 struct hostfs_iattr attrs;
795 char *name;
796 int err;
797
Christoph Hellwig10257742010-06-04 11:30:02 +0200798 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700799
Christoph Hellwig10257742010-06-04 11:30:02 +0200800 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 if (err)
802 return err;
803
Jeff Dike84b3db02007-10-16 01:27:13 -0700804 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 attr->ia_valid &= ~ATTR_SIZE;
806
807 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700808 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 attrs.ia_valid |= HOSTFS_ATTR_MODE;
810 attrs.ia_mode = attr->ia_mode;
811 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700812 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 attrs.ia_valid |= HOSTFS_ATTR_UID;
814 attrs.ia_uid = attr->ia_uid;
815 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700816 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 attrs.ia_valid |= HOSTFS_ATTR_GID;
818 attrs.ia_gid = attr->ia_gid;
819 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700820 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
822 attrs.ia_size = attr->ia_size;
823 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700824 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
826 attrs.ia_atime = attr->ia_atime;
827 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700828 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
830 attrs.ia_mtime = attr->ia_mtime;
831 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700832 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
834 attrs.ia_ctime = attr->ia_ctime;
835 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700836 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
838 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
841 }
842 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700843 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700844 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700845 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700847 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700848 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Christoph Hellwig10257742010-06-04 11:30:02 +0200850 if ((attr->ia_valid & ATTR_SIZE) &&
851 attr->ia_size != i_size_read(inode)) {
852 int error;
853
854 error = vmtruncate(inode, attr->ia_size);
855 if (err)
856 return err;
857 }
858
859 setattr_copy(inode, attr);
860 mark_inode_dirty(inode);
861 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862}
863
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800864static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 .create = hostfs_create,
866 .link = hostfs_link,
867 .unlink = hostfs_unlink,
868 .symlink = hostfs_symlink,
869 .mkdir = hostfs_mkdir,
870 .rmdir = hostfs_rmdir,
871 .mknod = hostfs_mknod,
872 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 .permission = hostfs_permission,
874 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875};
876
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800877static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 .create = hostfs_create,
879 .lookup = hostfs_lookup,
880 .link = hostfs_link,
881 .unlink = hostfs_unlink,
882 .symlink = hostfs_symlink,
883 .mkdir = hostfs_mkdir,
884 .rmdir = hostfs_rmdir,
885 .mknod = hostfs_mknod,
886 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 .permission = hostfs_permission,
888 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889};
890
891int hostfs_link_readpage(struct file *file, struct page *page)
892{
893 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 int err;
895
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 buffer = kmap(page);
897 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700898 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700899 return -ENOMEM;
WANG Congea7e7432008-11-19 15:36:46 -0800900 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700902 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700904 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 flush_dcache_page(page);
906 SetPageUptodate(page);
907 if (PageError(page)) ClearPageError(page);
908 err = 0;
909 }
910 kunmap(page);
911 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700912 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913}
914
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700915static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 .readpage = hostfs_link_readpage,
917};
918
919static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
920{
921 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700922 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 int err;
924
925 sb->s_blocksize = 1024;
926 sb->s_blocksize_bits = 10;
927 sb->s_magic = HOSTFS_SUPER_MAGIC;
928 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700929 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800931 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700932 if (req_root == NULL)
933 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
935 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400936 sb->s_fs_info = host_root_path =
937 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700938 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 goto out;
940
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700941 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Al Viro52b209f2010-06-06 18:43:19 -0400943 root_inode = new_inode(sb);
944 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400945 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
Al Viro52b209f2010-06-06 18:43:19 -0400947 root_inode->i_op = &hostfs_dir_iops;
948 root_inode->i_fop = &hostfs_dir_fops;
949
950 if (file_type(host_root_path, NULL, NULL) == OS_TYPE_SYMLINK) {
951 char *name = follow_link(host_root_path);
952 if (IS_ERR(name))
953 err = PTR_ERR(name);
954 else
955 err = read_name(root_inode, name);
956 kfree(name);
957 } else {
958 err = read_name(root_inode, host_root_path);
959 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700960 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 goto out_put;
962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 err = -ENOMEM;
964 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700965 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 goto out_put;
967
Jeff Dikef1adc052007-05-08 00:23:18 -0700968 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Jeff Dikef1adc052007-05-08 00:23:18 -0700970out_put:
971 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700972out:
973 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
David Howells454e2392006-06-23 02:02:57 -0700976static int hostfs_read_sb(struct file_system_type *type,
977 int flags, const char *dev_name,
978 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
David Howells454e2392006-06-23 02:02:57 -0700980 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981}
982
Al Viro601d2c32010-06-06 17:53:01 -0400983static void hostfs_kill_sb(struct super_block *s)
984{
985 kill_anon_super(s);
986 kfree(s->s_fs_info);
987}
988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989static struct file_system_type hostfs_type = {
990 .owner = THIS_MODULE,
991 .name = "hostfs",
992 .get_sb = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400993 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 .fs_flags = 0,
995};
996
997static int __init init_hostfs(void)
998{
Jeff Dikef1adc052007-05-08 00:23:18 -0700999 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000}
1001
1002static void __exit exit_hostfs(void)
1003{
1004 unregister_filesystem(&hostfs_type);
1005}
1006
1007module_init(init_hostfs)
1008module_exit(exit_hostfs)
1009MODULE_LICENSE("GPL");