blob: 7e6750499b8b12f113197e85195093181aeda6dd [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 int hostfs_read_inode(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 char *name;
210 int err = 0;
211
Jeff Dike84b3db02007-10-16 01:27:13 -0700212 /*
213 * Unfortunately, we are called from iget() when we don't have a dentry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 * allocated yet.
215 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700216 if (list_empty(&ino->i_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 goto out;
218
219 err = -ENOMEM;
220 name = inode_name(ino, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700221 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 goto out;
223
Jeff Dike84b3db02007-10-16 01:27:13 -0700224 if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 name = follow_link(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700226 if (IS_ERR(name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 err = PTR_ERR(name);
228 goto out;
229 }
230 }
231
232 err = read_name(ino, name);
233 kfree(name);
234 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700235 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236}
237
David Howells0a370e52008-02-07 00:15:50 -0800238static struct inode *hostfs_iget(struct super_block *sb)
239{
240 struct inode *inode;
241 long ret;
242
Al Viroe971a6d2010-06-06 15:16:17 -0400243 inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800244 if (!inode)
245 return ERR_PTR(-ENOMEM);
Al Viroe971a6d2010-06-06 15:16:17 -0400246 ret = hostfs_read_inode(inode);
247 if (ret < 0) {
248 iput(inode);
249 return ERR_PTR(ret);
David Howells0a370e52008-02-07 00:15:50 -0800250 }
251 return inode;
252}
253
David Howells726c3342006-06-23 02:02:58 -0700254int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
Jeff Dike84b3db02007-10-16 01:27:13 -0700256 /*
257 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 * struct statfs still has 32-bit versions for most of these fields,
259 * so we convert them here
260 */
261 int err;
262 long long f_blocks;
263 long long f_bfree;
264 long long f_bavail;
265 long long f_files;
266 long long f_ffree;
267
Al Viro601d2c32010-06-06 17:53:01 -0400268 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
270 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
271 &sf->f_namelen, sf->f_spare);
Jeff Dike84b3db02007-10-16 01:27:13 -0700272 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700273 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 sf->f_blocks = f_blocks;
275 sf->f_bfree = f_bfree;
276 sf->f_bavail = f_bavail;
277 sf->f_files = f_files;
278 sf->f_ffree = f_ffree;
279 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700280 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281}
282
283static struct inode *hostfs_alloc_inode(struct super_block *sb)
284{
285 struct hostfs_inode_info *hi;
286
Al Viro601d2c32010-06-06 17:53:01 -0400287 hi = kzalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700288 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700289 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400290 hi->fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700292 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
Al Viroe971a6d2010-06-06 15:16:17 -0400295static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
Mark Fashehfef26652005-09-09 13:01:31 -0700297 truncate_inode_pages(&inode->i_data, 0);
Al Viroe971a6d2010-06-06 15:16:17 -0400298 end_writeback(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700299 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 close_file(&HOSTFS_I(inode)->fd);
301 HOSTFS_I(inode)->fd = -1;
302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303}
304
305static void hostfs_destroy_inode(struct inode *inode)
306{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 kfree(HOSTFS_I(inode));
308}
309
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800310static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
311{
Al Viro601d2c32010-06-06 17:53:01 -0400312 const char *root_path = vfs->mnt_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800313 size_t offset = strlen(root_ino) + 1;
314
315 if (strlen(root_path) > offset)
316 seq_printf(seq, ",%s", root_path + offset);
317
318 return 0;
319}
320
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800321static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400324 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800326 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327};
328
329int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
330{
331 void *dir;
332 char *name;
333 unsigned long long next, ino;
334 int error, len;
335
Josef Sipek680b0da2006-12-08 02:37:05 -0800336 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700337 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700338 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 dir = open_dir(name, &error);
340 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700341 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700342 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700344 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 error = (*filldir)(ent, name, len, file->f_pos,
346 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700347 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 file->f_pos = next;
349 }
350 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700351 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352}
353
354int hostfs_file_open(struct inode *ino, struct file *file)
355{
356 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400357 fmode_t mode = 0;
358 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700361 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700362 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Jeff Dike84b3db02007-10-16 01:27:13 -0700364 /*
365 * The file may already have been opened, but with the wrong access,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 * so this resets things and reopens the file with the new access.
367 */
Jeff Dike84b3db02007-10-16 01:27:13 -0700368 if (HOSTFS_I(ino)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 close_file(&HOSTFS_I(ino)->fd);
370 HOSTFS_I(ino)->fd = -1;
371 }
372
373 HOSTFS_I(ino)->mode |= mode;
Jeff Dike84b3db02007-10-16 01:27:13 -0700374 if (HOSTFS_I(ino)->mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 r = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700376 if (HOSTFS_I(ino)->mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700378 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 r = 1;
380
Josef Sipek680b0da2006-12-08 02:37:05 -0800381 name = dentry_name(file->f_path.dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700382 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700383 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 fd = open_file(name, r, w, append);
386 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700387 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700388 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 FILE_HOSTFS_I(file)->fd = fd;
390
Jeff Dikef1adc052007-05-08 00:23:18 -0700391 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392}
393
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200394int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200396 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397}
398
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800399static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700401 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200402 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 .aio_read = generic_file_aio_read,
404 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700405 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 .mmap = generic_file_mmap,
407 .open = hostfs_file_open,
408 .release = NULL,
409 .fsync = hostfs_fsync,
410};
411
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800412static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 .llseek = generic_file_llseek,
414 .readdir = hostfs_readdir,
415 .read = generic_read_dir,
416};
417
418int hostfs_writepage(struct page *page, struct writeback_control *wbc)
419{
420 struct address_space *mapping = page->mapping;
421 struct inode *inode = mapping->host;
422 char *buffer;
423 unsigned long long base;
424 int count = PAGE_CACHE_SIZE;
425 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
426 int err;
427
428 if (page->index >= end_index)
429 count = inode->i_size & (PAGE_CACHE_SIZE-1);
430
431 buffer = kmap(page);
432 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
433
434 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700435 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 ClearPageUptodate(page);
437 goto out;
438 }
439
440 if (base > inode->i_size)
441 inode->i_size = base;
442
443 if (PageError(page))
444 ClearPageError(page);
445 err = 0;
446
447 out:
448 kunmap(page);
449
450 unlock_page(page);
451 return err;
452}
453
454int hostfs_readpage(struct file *file, struct page *page)
455{
456 char *buffer;
457 long long start;
458 int err = 0;
459
460 start = (long long) page->index << PAGE_CACHE_SHIFT;
461 buffer = kmap(page);
462 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
463 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700464 if (err < 0)
465 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
468
469 flush_dcache_page(page);
470 SetPageUptodate(page);
471 if (PageError(page)) ClearPageError(page);
472 err = 0;
473 out:
474 kunmap(page);
475 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700476 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477}
478
Nick Pigginae361ff2007-10-16 01:25:17 -0700479int hostfs_write_begin(struct file *file, struct address_space *mapping,
480 loff_t pos, unsigned len, unsigned flags,
481 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Nick Pigginae361ff2007-10-16 01:25:17 -0700483 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Nick Piggin54566b22009-01-04 12:00:53 -0800485 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700486 if (!*pagep)
487 return -ENOMEM;
488 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
490
Nick Pigginae361ff2007-10-16 01:25:17 -0700491int hostfs_write_end(struct file *file, struct address_space *mapping,
492 loff_t pos, unsigned len, unsigned copied,
493 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700496 void *buffer;
497 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
498 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700501 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700503
504 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
505 SetPageUptodate(page);
506
Jeff Dike84b3db02007-10-16 01:27:13 -0700507 /*
508 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700509 * i_size against the last byte written.
510 */
511 if (err > 0 && (pos > inode->i_size))
512 inode->i_size = pos;
513 unlock_page(page);
514 page_cache_release(page);
515
Jeff Dikef1adc052007-05-08 00:23:18 -0700516 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517}
518
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700519static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 .writepage = hostfs_writepage,
521 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700522 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700523 .write_begin = hostfs_write_begin,
524 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525};
526
527static int init_inode(struct inode *inode, struct dentry *dentry)
528{
529 char *name;
530 int type, err = -ENOMEM;
531 int maj, min;
532 dev_t rdev = 0;
533
Jeff Dike84b3db02007-10-16 01:27:13 -0700534 if (dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700536 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 goto out;
538 type = file_type(name, &maj, &min);
Jeff Dike84b3db02007-10-16 01:27:13 -0700539 /* Reencode maj and min with the kernel encoding.*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 rdev = MKDEV(maj, min);
541 kfree(name);
542 }
543 else type = OS_TYPE_DIR;
544
545 err = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700546 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 inode->i_op = &page_symlink_inode_operations;
Jeff Dike84b3db02007-10-16 01:27:13 -0700548 else if (type == OS_TYPE_DIR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 inode->i_op = &hostfs_dir_iops;
550 else inode->i_op = &hostfs_iops;
551
Jeff Dike84b3db02007-10-16 01:27:13 -0700552 if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 else inode->i_fop = &hostfs_file_fops;
554
Jeff Dike84b3db02007-10-16 01:27:13 -0700555 if (type == OS_TYPE_SYMLINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 inode->i_mapping->a_ops = &hostfs_link_aops;
557 else inode->i_mapping->a_ops = &hostfs_aops;
558
559 switch (type) {
560 case OS_TYPE_CHARDEV:
561 init_special_inode(inode, S_IFCHR, rdev);
562 break;
563 case OS_TYPE_BLOCKDEV:
564 init_special_inode(inode, S_IFBLK, rdev);
565 break;
566 case OS_TYPE_FIFO:
567 init_special_inode(inode, S_IFIFO, 0);
568 break;
569 case OS_TYPE_SOCK:
570 init_special_inode(inode, S_IFSOCK, 0);
571 break;
572 }
573 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700574 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576
577int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700578 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
580 struct inode *inode;
581 char *name;
582 int error, fd;
583
David Howells0a370e52008-02-07 00:15:50 -0800584 inode = hostfs_iget(dir->i_sb);
585 if (IS_ERR(inode)) {
586 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700587 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
590 error = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700591 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 goto out_put;
593
594 error = -ENOMEM;
595 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700596 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 goto out_put;
598
599 fd = file_create(name,
600 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
601 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
602 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Jeff Dike84b3db02007-10-16 01:27:13 -0700603 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 error = fd;
605 else error = read_name(inode, name);
606
607 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700608 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 goto out_put;
610
611 HOSTFS_I(inode)->fd = fd;
612 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
613 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700614 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 out_put:
617 iput(inode);
618 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700619 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620}
621
622struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700623 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
625 struct inode *inode;
626 char *name;
627 int err;
628
David Howells0a370e52008-02-07 00:15:50 -0800629 inode = hostfs_iget(ino->i_sb);
630 if (IS_ERR(inode)) {
631 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
635 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700636 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 goto out_put;
638
639 err = -ENOMEM;
640 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700641 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 goto out_put;
643
644 err = read_name(inode, name);
645 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700646 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 iput(inode);
648 inode = NULL;
649 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700650 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 goto out_put;
652
653 d_add(dentry, inode);
654 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657 out_put:
658 iput(inode);
659 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700660 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661}
662
663static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
664{
Jeff Dikef1adc052007-05-08 00:23:18 -0700665 char *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 int len;
667
668 file = inode_name(ino, dentry->d_name.len + 1);
Jeff Dike84b3db02007-10-16 01:27:13 -0700669 if (file == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700670 return NULL;
671 strcat(file, "/");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 len = strlen(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700673 strncat(file, dentry->d_name.name, dentry->d_name.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 file[len + dentry->d_name.len] = '\0';
Jeff Dikef1adc052007-05-08 00:23:18 -0700675 return file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676}
677
678int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
679{
Jeff Dikef1adc052007-05-08 00:23:18 -0700680 char *from_name, *to_name;
681 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Jeff Dike84b3db02007-10-16 01:27:13 -0700683 if ((from_name = inode_dentry_name(ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700684 return -ENOMEM;
685 to_name = dentry_name(to, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700686 if (to_name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700690 err = link_file(to_name, from_name);
691 kfree(from_name);
692 kfree(to_name);
693 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694}
695
696int hostfs_unlink(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;
Jeff Dike84b3db02007-10-16 01:27:13 -0700703 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700704 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 err = unlink_file(file);
707 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700708 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
710
711int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
712{
713 char *file;
714 int err;
715
Jeff Dike84b3db02007-10-16 01:27:13 -0700716 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700717 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 err = make_symlink(file, to);
719 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700720 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721}
722
723int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
724{
725 char *file;
726 int err;
727
Jeff Dike84b3db02007-10-16 01:27:13 -0700728 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700729 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 err = do_mkdir(file, mode);
731 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700732 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733}
734
735int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
736{
737 char *file;
738 int err;
739
Jeff Dike84b3db02007-10-16 01:27:13 -0700740 if ((file = inode_dentry_name(ino, dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700741 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 err = do_rmdir(file);
743 kfree(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700744 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
746
747int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
748{
749 struct inode *inode;
750 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800751 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
David Howells0a370e52008-02-07 00:15:50 -0800753 inode = hostfs_iget(dir->i_sb);
754 if (IS_ERR(inode)) {
755 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
759 err = init_inode(inode, dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700760 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 goto out_put;
762
763 err = -ENOMEM;
764 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700765 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 goto out_put;
767
768 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800769 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Jeff Dike84b3db02007-10-16 01:27:13 -0700770 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 goto out_free;
772
773 err = read_name(inode, name);
774 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700775 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 goto out_put;
777
778 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700779 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 out_free:
782 kfree(name);
783 out_put:
784 iput(inode);
785 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700786 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787}
788
789int hostfs_rename(struct inode *from_ino, struct dentry *from,
790 struct inode *to_ino, struct dentry *to)
791{
792 char *from_name, *to_name;
793 int err;
794
Jeff Dike84b3db02007-10-16 01:27:13 -0700795 if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700796 return -ENOMEM;
Jeff Dike84b3db02007-10-16 01:27:13 -0700797 if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 kfree(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700799 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 }
801 err = rename_file(from_name, to_name);
802 kfree(from_name);
803 kfree(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700804 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805}
806
Al Viroe6305c42008-07-15 21:03:57 -0400807int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
809 char *name;
810 int r = 0, w = 0, x = 0, err;
811
812 if (desired & MAY_READ) r = 1;
813 if (desired & MAY_WRITE) w = 1;
814 if (desired & MAY_EXEC) x = 1;
815 name = inode_name(ino, 0);
Jeff Dikef1adc052007-05-08 00:23:18 -0700816 if (name == NULL)
817 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700820 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 err = 0;
822 else
823 err = access_file(name, r, w, x);
824 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700825 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 err = generic_permission(ino, desired, NULL);
827 return err;
828}
829
830int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
831{
Christoph Hellwig10257742010-06-04 11:30:02 +0200832 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 struct hostfs_iattr attrs;
834 char *name;
835 int err;
836
Christoph Hellwig10257742010-06-04 11:30:02 +0200837 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700838
Christoph Hellwig10257742010-06-04 11:30:02 +0200839 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (err)
841 return err;
842
Jeff Dike84b3db02007-10-16 01:27:13 -0700843 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 attr->ia_valid &= ~ATTR_SIZE;
845
846 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700847 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 attrs.ia_valid |= HOSTFS_ATTR_MODE;
849 attrs.ia_mode = attr->ia_mode;
850 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700851 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 attrs.ia_valid |= HOSTFS_ATTR_UID;
853 attrs.ia_uid = attr->ia_uid;
854 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700855 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 attrs.ia_valid |= HOSTFS_ATTR_GID;
857 attrs.ia_gid = attr->ia_gid;
858 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700859 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
861 attrs.ia_size = attr->ia_size;
862 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700863 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
865 attrs.ia_atime = attr->ia_atime;
866 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700867 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
869 attrs.ia_mtime = attr->ia_mtime;
870 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700871 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
873 attrs.ia_ctime = attr->ia_ctime;
874 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700875 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
877 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700878 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
880 }
881 name = dentry_name(dentry, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700882 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700883 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700884 err = set_attr(name, &attrs, fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700886 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700887 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
Christoph Hellwig10257742010-06-04 11:30:02 +0200889 if ((attr->ia_valid & ATTR_SIZE) &&
890 attr->ia_size != i_size_read(inode)) {
891 int error;
892
893 error = vmtruncate(inode, attr->ia_size);
894 if (err)
895 return err;
896 }
897
898 setattr_copy(inode, attr);
899 mark_inode_dirty(inode);
900 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901}
902
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800903static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 .create = hostfs_create,
905 .link = hostfs_link,
906 .unlink = hostfs_unlink,
907 .symlink = hostfs_symlink,
908 .mkdir = hostfs_mkdir,
909 .rmdir = hostfs_rmdir,
910 .mknod = hostfs_mknod,
911 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 .permission = hostfs_permission,
913 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914};
915
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800916static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 .create = hostfs_create,
918 .lookup = hostfs_lookup,
919 .link = hostfs_link,
920 .unlink = hostfs_unlink,
921 .symlink = hostfs_symlink,
922 .mkdir = hostfs_mkdir,
923 .rmdir = hostfs_rmdir,
924 .mknod = hostfs_mknod,
925 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 .permission = hostfs_permission,
927 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928};
929
930int hostfs_link_readpage(struct file *file, struct page *page)
931{
932 char *buffer, *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 int err;
934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 buffer = kmap(page);
936 name = inode_name(page->mapping->host, 0);
Jeff Dike84b3db02007-10-16 01:27:13 -0700937 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700938 return -ENOMEM;
WANG Congea7e7432008-11-19 15:36:46 -0800939 err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 kfree(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700941 if (err == PAGE_CACHE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 err = -E2BIG;
Jeff Dike84b3db02007-10-16 01:27:13 -0700943 else if (err > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 flush_dcache_page(page);
945 SetPageUptodate(page);
946 if (PageError(page)) ClearPageError(page);
947 err = 0;
948 }
949 kunmap(page);
950 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700951 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952}
953
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700954static const struct address_space_operations hostfs_link_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 .readpage = hostfs_link_readpage,
956};
957
958static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
959{
960 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700961 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 int err;
963
964 sb->s_blocksize = 1024;
965 sb->s_blocksize_bits = 10;
966 sb->s_magic = HOSTFS_SUPER_MAGIC;
967 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700968 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800970 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700971 if (req_root == NULL)
972 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400975 sb->s_fs_info = host_root_path =
976 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700977 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 goto out;
979
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700980 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
David Howells0a370e52008-02-07 00:15:50 -0800982 root_inode = hostfs_iget(sb);
983 if (IS_ERR(root_inode)) {
984 err = PTR_ERR(root_inode);
Al Viro601d2c32010-06-06 17:53:01 -0400985 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 err = init_inode(root_inode, NULL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700989 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 goto out_put;
991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 err = -ENOMEM;
993 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700994 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 goto out_put;
996
David Howells0a370e52008-02-07 00:15:50 -0800997 err = hostfs_read_inode(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700998 if (err) {
Jeff Dikef1adc052007-05-08 00:23:18 -0700999 /* No iput in this case because the dput does that for us */
1000 dput(sb->s_root);
1001 sb->s_root = NULL;
Paolo 'Blaisorblade' Giarrussobca27112007-03-07 20:41:07 -08001002 goto out;
Jeff Dikef1adc052007-05-08 00:23:18 -07001003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Jeff Dikef1adc052007-05-08 00:23:18 -07001005 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Jeff Dikef1adc052007-05-08 00:23:18 -07001007out_put:
1008 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -07001009out:
1010 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011}
1012
David Howells454e2392006-06-23 02:02:57 -07001013static int hostfs_read_sb(struct file_system_type *type,
1014 int flags, const char *dev_name,
1015 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016{
David Howells454e2392006-06-23 02:02:57 -07001017 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018}
1019
Al Viro601d2c32010-06-06 17:53:01 -04001020static void hostfs_kill_sb(struct super_block *s)
1021{
1022 kill_anon_super(s);
1023 kfree(s->s_fs_info);
1024}
1025
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026static struct file_system_type hostfs_type = {
1027 .owner = THIS_MODULE,
1028 .name = "hostfs",
1029 .get_sb = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -04001030 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 .fs_flags = 0,
1032};
1033
1034static int __init init_hostfs(void)
1035{
Jeff Dikef1adc052007-05-08 00:23:18 -07001036 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037}
1038
1039static void __exit exit_hostfs(void)
1040{
1041 unregister_filesystem(&hostfs_type);
1042}
1043
1044module_init(init_hostfs)
1045module_exit(exit_hostfs)
1046MODULE_LICENSE("GPL");