blob: 5a77ed3dfd7ec50b12d70cee044f6e4dcde648ef [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
Al Viro5e2df282010-06-06 19:38:18 -0400488static void init_inode(struct inode *inode, char *path)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
Al Viro5e2df282010-06-06 19:38:18 -0400490 int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 int maj, min;
492 dev_t rdev = 0;
493
Al Viro5e2df282010-06-06 19:38:18 -0400494 type = file_type(path, &maj, &min);
495 /* Reencode maj and min with the kernel encoding.*/
496 rdev = MKDEV(maj, min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
Jeff Dike84b3db02007-10-16 01:27:13 -0700498 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700500 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 inode->i_op = &hostfs_dir_iops;
502 else inode->i_op = &hostfs_iops;
503
Jeff Dike84b3db02007-10-16 01:27:13 -0700504 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 else inode->i_fop = &hostfs_file_fops;
506
Jeff Dike84b3db02007-10-16 01:27:13 -0700507 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 inode->i_mapping->a_ops = &hostfs_link_aops;
509 else inode->i_mapping->a_ops = &hostfs_aops;
510
511 switch (type) {
512 case OS_TYPE_CHARDEV:
513 init_special_inode(inode, S_IFCHR, rdev);
514 break;
515 case OS_TYPE_BLOCKDEV:
516 init_special_inode(inode, S_IFBLK, rdev);
517 break;
518 case OS_TYPE_FIFO:
519 init_special_inode(inode, S_IFIFO, 0);
520 break;
521 case OS_TYPE_SOCK:
522 init_special_inode(inode, S_IFSOCK, 0);
523 break;
524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525}
526
527int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700528 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529{
530 struct inode *inode;
531 char *name;
532 int error, fd;
533
David Howells0a370e52008-02-07 00:15:50 -0800534 inode = hostfs_iget(dir->i_sb);
535 if (IS_ERR(inode)) {
536 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700537 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 error = -ENOMEM;
541 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700542 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 goto out_put;
544
545 fd = file_create(name,
546 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
547 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
548 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro5e2df282010-06-06 19:38:18 -0400549 if (fd < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 error = fd;
Al Viro5e2df282010-06-06 19:38:18 -0400551 } else {
552 error = read_name(inode, name);
553 init_inode(inode, name);
554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700557 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 goto out_put;
559
560 HOSTFS_I(inode)->fd = fd;
561 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
562 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700563 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
565 out_put:
566 iput(inode);
567 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700568 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569}
570
571struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700572 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 struct inode *inode;
575 char *name;
576 int err;
577
David Howells0a370e52008-02-07 00:15:50 -0800578 inode = hostfs_iget(ino->i_sb);
579 if (IS_ERR(inode)) {
580 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 err = -ENOMEM;
585 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700586 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 goto out_put;
588
589 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400590 init_inode(inode, name);
591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700593 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 iput(inode);
595 inode = NULL;
596 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700597 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 goto out_put;
599
600 d_add(dentry, inode);
601 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700602 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 out_put:
605 iput(inode);
606 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700607 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608}
609
610static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
611{
Jeff Dikef1adc052007-05-08 00:23:18 -0700612 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 int len;
614
615 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700616 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700617 return NULL;
618 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700620 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700622 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623}
624
625int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
626{
Jeff Dikef1adc052007-05-08 00:23:18 -0700627 char *from_name, *to_name;
628 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Jeff Dike84b3db02007-10-16 01:27:13 -0700630 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700631 return -ENOMEM;
632 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700633 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700635 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700637 err = link_file(to_name, from_name);
638 kfree(from_name);
639 kfree(to_name);
640 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
643int hostfs_unlink(struct inode *ino, struct dentry *dentry)
644{
645 char *file;
646 int err;
647
Jeff Dike84b3db02007-10-16 01:27:13 -0700648 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700650 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700651 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 err = unlink_file(file);
654 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
657
658int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
659{
660 char *file;
661 int err;
662
Jeff Dike84b3db02007-10-16 01:27:13 -0700663 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700664 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 err = make_symlink(file, to);
666 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700667 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668}
669
670int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
671{
672 char *file;
673 int err;
674
Jeff Dike84b3db02007-10-16 01:27:13 -0700675 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 err = do_mkdir(file, mode);
678 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700679 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
682int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
683{
684 char *file;
685 int err;
686
Jeff Dike84b3db02007-10-16 01:27:13 -0700687 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 err = do_rmdir(file);
690 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700691 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692}
693
694int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
695{
696 struct inode *inode;
697 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800698 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
David Howells0a370e52008-02-07 00:15:50 -0800700 inode = hostfs_iget(dir->i_sb);
701 if (IS_ERR(inode)) {
702 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800704 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 err = -ENOMEM;
707 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700708 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 goto out_put;
710
711 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800712 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700713 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 goto out_free;
715
716 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400717 init_inode(inode, name);
718 if (err)
719 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700721 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 goto out_put;
723
724 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700725 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 out_free:
728 kfree(name);
729 out_put:
730 iput(inode);
731 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700732 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733}
734
735int hostfs_rename(struct inode *from_ino, struct dentry *from,
736 struct inode *to_ino, struct dentry *to)
737{
738 char *from_name, *to_name;
739 int err;
740
Jeff Dike84b3db02007-10-16 01:27:13 -0700741 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700742 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700743 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700745 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 }
747 err = rename_file(from_name, to_name);
748 kfree(from_name);
749 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700750 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751}
752
Al Viroe6305c42008-07-15 21:03:57 -0400753int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754{
755 char *name;
756 int r = 0, w = 0, x = 0, err;
757
758 if (desired & MAY_READ) r = 1;
759 if (desired & MAY_WRITE) w = 1;
760 if (desired & MAY_EXEC) x = 1;
761 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700762 if (name == NULL)
763 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700766 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 err = 0;
768 else
769 err = access_file(name, r, w, x);
770 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700771 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 err = generic_permission(ino, desired, NULL);
773 return err;
774}
775
776int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
777{
Christoph Hellwig10257742010-06-04 11:30:02 +0200778 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 struct hostfs_iattr attrs;
780 char *name;
781 int err;
782
Christoph Hellwig10257742010-06-04 11:30:02 +0200783 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700784
Christoph Hellwig10257742010-06-04 11:30:02 +0200785 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (err)
787 return err;
788
Jeff Dike84b3db02007-10-16 01:27:13 -0700789 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 attr->ia_valid &= ~ATTR_SIZE;
791
792 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700793 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 attrs.ia_valid |= HOSTFS_ATTR_MODE;
795 attrs.ia_mode = attr->ia_mode;
796 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700797 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 attrs.ia_valid |= HOSTFS_ATTR_UID;
799 attrs.ia_uid = attr->ia_uid;
800 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700801 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 attrs.ia_valid |= HOSTFS_ATTR_GID;
803 attrs.ia_gid = attr->ia_gid;
804 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700805 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
807 attrs.ia_size = attr->ia_size;
808 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700809 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
811 attrs.ia_atime = attr->ia_atime;
812 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700813 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
815 attrs.ia_mtime = attr->ia_mtime;
816 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700817 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
819 attrs.ia_ctime = attr->ia_ctime;
820 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700821 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
823 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700824 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
826 }
827 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700828 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700829 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700830 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700832 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700833 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
Christoph Hellwig10257742010-06-04 11:30:02 +0200835 if ((attr->ia_valid & ATTR_SIZE) &&
836 attr->ia_size != i_size_read(inode)) {
837 int error;
838
839 error = vmtruncate(inode, attr->ia_size);
840 if (err)
841 return err;
842 }
843
844 setattr_copy(inode, attr);
845 mark_inode_dirty(inode);
846 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847}
848
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800849static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 .create = hostfs_create,
851 .link = hostfs_link,
852 .unlink = hostfs_unlink,
853 .symlink = hostfs_symlink,
854 .mkdir = hostfs_mkdir,
855 .rmdir = hostfs_rmdir,
856 .mknod = hostfs_mknod,
857 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 .permission = hostfs_permission,
859 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860};
861
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800862static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 .create = hostfs_create,
864 .lookup = hostfs_lookup,
865 .link = hostfs_link,
866 .unlink = hostfs_unlink,
867 .symlink = hostfs_symlink,
868 .mkdir = hostfs_mkdir,
869 .rmdir = hostfs_rmdir,
870 .mknod = hostfs_mknod,
871 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 .permission = hostfs_permission,
873 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874};
875
876int hostfs_link_readpage(struct file *file, struct page *page)
877{
878 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 int err;
880
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 buffer = kmap(page);
882 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700883 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700884 return -ENOMEM;
WANG Congea7e7432008-11-19 15:36:46 -0800885 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700887 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700889 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 flush_dcache_page(page);
891 SetPageUptodate(page);
892 if (PageError(page)) ClearPageError(page);
893 err = 0;
894 }
895 kunmap(page);
896 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700897 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898}
899
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700900static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 .readpage = hostfs_link_readpage,
902};
903
904static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
905{
906 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700907 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 int err;
909
910 sb->s_blocksize = 1024;
911 sb->s_blocksize_bits = 10;
912 sb->s_magic = HOSTFS_SUPER_MAGIC;
913 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700914 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800916 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700917 if (req_root == NULL)
918 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
920 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400921 sb->s_fs_info = host_root_path =
922 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700923 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 goto out;
925
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700926 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Al Viro52b209f2010-06-06 18:43:19 -0400928 root_inode = new_inode(sb);
929 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400930 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Al Viro52b209f2010-06-06 18:43:19 -0400932 root_inode->i_op = &hostfs_dir_iops;
933 root_inode->i_fop = &hostfs_dir_fops;
934
935 if (file_type(host_root_path, NULL, NULL) == OS_TYPE_SYMLINK) {
936 char *name = follow_link(host_root_path);
937 if (IS_ERR(name))
938 err = PTR_ERR(name);
939 else
940 err = read_name(root_inode, name);
941 kfree(name);
942 } else {
943 err = read_name(root_inode, host_root_path);
944 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700945 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 goto out_put;
947
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 err = -ENOMEM;
949 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700950 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 goto out_put;
952
Jeff Dikef1adc052007-05-08 00:23:18 -0700953 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Jeff Dikef1adc052007-05-08 00:23:18 -0700955out_put:
956 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700957out:
958 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
David Howells454e2392006-06-23 02:02:57 -0700961static int hostfs_read_sb(struct file_system_type *type,
962 int flags, const char *dev_name,
963 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964{
David Howells454e2392006-06-23 02:02:57 -0700965 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
Al Viro601d2c32010-06-06 17:53:01 -0400968static void hostfs_kill_sb(struct super_block *s)
969{
970 kill_anon_super(s);
971 kfree(s->s_fs_info);
972}
973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974static struct file_system_type hostfs_type = {
975 .owner = THIS_MODULE,
976 .name = "hostfs",
977 .get_sb = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400978 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 .fs_flags = 0,
980};
981
982static int __init init_hostfs(void)
983{
Jeff Dikef1adc052007-05-08 00:23:18 -0700984 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985}
986
987static void __exit exit_hostfs(void)
988{
989 unregister_filesystem(&hostfs_type);
990}
991
992module_init(init_hostfs)
993module_exit(exit_hostfs)
994MODULE_LICENSE("GPL");