blob: cd7c93917cc7c29636ee7c87a8846177e4098d23 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jeff Dikef1adc052007-05-08 00:23:18 -07002 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 *
5 * Ported the filesystem routines to 2.5.
6 * 2003-02-10 Petr Baudis <pasky@ucw.cz>
7 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/module.h>
Jeff Dike84b3db02007-10-16 01:27:13 -070011#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/statfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -080015#include <linux/seq_file.h>
Jiri Kosina6966a972008-02-09 00:10:14 -080016#include <linux/mount.h>
Al Virod0352d32010-06-06 21:51:16 -040017#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "hostfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include "init.h"
Jeff Dike84b3db02007-10-16 01:27:13 -070020#include "kern.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22struct hostfs_inode_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 int fd;
Al Viroaeb5d722008-09-02 15:28:45 -040024 fmode_t mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 struct inode vfs_inode;
26};
27
28static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
29{
Jeff Dikef1adc052007-05-08 00:23:18 -070030 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031}
32
Josef Sipek680b0da2006-12-08 02:37:05 -080033#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Al Viroe16404e2009-02-20 05:55:13 +000035static int hostfs_d_delete(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -070036{
Jeff Dikef1adc052007-05-08 00:23:18 -070037 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038}
39
Al Viroe16404e2009-02-20 05:55:13 +000040static const struct dentry_operations hostfs_dentry_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 .d_delete = hostfs_d_delete,
42};
43
44/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080045static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070046static int append = 0;
47
48#define HOSTFS_SUPER_MAGIC 0x00c0ffee
49
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080050static const struct inode_operations hostfs_iops;
51static const struct inode_operations hostfs_dir_iops;
Al Virod0352d32010-06-06 21:51:16 -040052static const struct inode_operations hostfs_link_iops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54#ifndef MODULE
55static int __init hostfs_args(char *options, int *add)
56{
57 char *ptr;
58
59 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070060 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070062 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 root_ino = options;
64
65 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070066 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070068 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070070 if (*options != '\0') {
71 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 append = 1;
73 else printf("hostfs_args - unsupported option - %s\n",
74 options);
75 }
76 options = ptr;
77 }
Jeff Dikef1adc052007-05-08 00:23:18 -070078 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079}
80
81__uml_setup("hostfs=", hostfs_args,
82"hostfs=<root dir>,<flags>,...\n"
83" This is used to set hostfs parameters. The root directory argument\n"
84" is used to confine all hostfs mounts to within the specified directory\n"
85" tree on the host. If this isn't specified, then a user inside UML can\n"
86" mount anything on the host that's accessible to the user that's running\n"
87" it.\n"
88" The only flag currently supported is 'append', which specifies that all\n"
89" files opened by hostfs will be opened in append mode.\n\n"
90);
91#endif
92
Al Viroe9193052010-06-06 23:16:34 -040093static char *__dentry_name(struct dentry *dentry, char *name)
94{
95 char *p = __dentry_path(dentry, name, PATH_MAX);
96 char *root;
97 size_t len;
98
99 spin_unlock(&dcache_lock);
100
101 root = dentry->d_sb->s_fs_info;
102 len = strlen(root);
103 if (IS_ERR(p)) {
104 __putname(name);
105 return NULL;
106 }
Al Viro850a4962010-08-18 06:18:57 -0400107 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -0400108 if (len > p - name) {
109 __putname(name);
110 return NULL;
111 }
112 if (p > name + len) {
113 char *s = name + len;
114 while ((*s++ = *p++) != '\0')
115 ;
116 }
117 return name;
118}
119
Al Viroc5322222010-06-06 20:42:10 -0400120static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
Al Viroe9193052010-06-06 23:16:34 -0400122 char *name = __getname();
123 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700124 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Al Viroe9193052010-06-06 23:16:34 -0400126 spin_lock(&dcache_lock);
127 return __dentry_name(dentry, name); /* will unlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128}
129
Al Viroc5322222010-06-06 20:42:10 -0400130static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
132 struct dentry *dentry;
Al Viroe9193052010-06-06 23:16:34 -0400133 char *name = __getname();
134 if (!name)
135 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Al Viroe9193052010-06-06 23:16:34 -0400137 spin_lock(&dcache_lock);
138 if (list_empty(&ino->i_dentry)) {
139 spin_unlock(&dcache_lock);
140 __putname(name);
141 return NULL;
142 }
143 dentry = list_first_entry(&ino->i_dentry, struct dentry, d_alias);
144 return __dentry_name(dentry, name); /* will unlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145}
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static char *follow_link(char *link)
148{
149 int len, n;
150 char *name, *resolved, *end;
151
152 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700153 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 n = -ENOMEM;
155 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700156 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 goto out;
158
WANG Congea7e7432008-11-19 15:36:46 -0800159 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700160 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 break;
162 len *= 2;
163 kfree(name);
164 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700165 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 goto out_free;
167
Jeff Dike84b3db02007-10-16 01:27:13 -0700168 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700169 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700172 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700173 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175 *(end + 1) = '\0';
176 len = strlen(link) + strlen(name) + 1;
177
178 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700179 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 n = -ENOMEM;
181 goto out_free;
182 }
183
184 sprintf(resolved, "%s%s", link, name);
185 kfree(name);
186 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700187 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189 out_free:
190 kfree(name);
191 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700192 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
David Howells0a370e52008-02-07 00:15:50 -0800195static struct inode *hostfs_iget(struct super_block *sb)
196{
Al Viro52b209f72010-06-06 18:43:19 -0400197 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800198 if (!inode)
199 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800200 return inode;
201}
202
David Howells726c3342006-06-23 02:02:58 -0700203int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
Jeff Dike84b3db02007-10-16 01:27:13 -0700205 /*
206 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 * struct statfs still has 32-bit versions for most of these fields,
208 * so we convert them here
209 */
210 int err;
211 long long f_blocks;
212 long long f_bfree;
213 long long f_bavail;
214 long long f_files;
215 long long f_ffree;
216
Al Viro601d2c32010-06-06 17:53:01 -0400217 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
219 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700220 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700221 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700222 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 sf->f_blocks = f_blocks;
224 sf->f_bfree = f_bfree;
225 sf->f_bavail = f_bavail;
226 sf->f_files = f_files;
227 sf->f_ffree = f_ffree;
228 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700229 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230}
231
232static struct inode *hostfs_alloc_inode(struct super_block *sb)
233{
234 struct hostfs_inode_info *hi;
235
Al Viro601d2c32010-06-06 17:53:01 -0400236 hi = kzalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700237 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700238 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400239 hi->fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700241 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
Al Viroe971a6d2010-06-06 15:16:17 -0400244static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
Mark Fashehfef26652005-09-09 13:01:31 -0700246 truncate_inode_pages(&inode->i_data, 0);
Al Viroe971a6d2010-06-06 15:16:17 -0400247 end_writeback(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700248 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 close_file(&HOSTFS_I(inode)->fd);
250 HOSTFS_I(inode)->fd = -1;
251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252}
253
254static void hostfs_destroy_inode(struct inode *inode)
255{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 kfree(HOSTFS_I(inode));
257}
258
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800259static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
260{
Al Viro601d2c32010-06-06 17:53:01 -0400261 const char *root_path = vfs->mnt_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800262 size_t offset = strlen(root_ino) + 1;
263
264 if (strlen(root_path) > offset)
265 seq_printf(seq, ",%s", root_path + offset);
266
267 return 0;
268}
269
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800270static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400273 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800275 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276};
277
278int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
279{
280 void *dir;
281 char *name;
282 unsigned long long next, ino;
283 int error, len;
284
Al Viroc5322222010-06-06 20:42:10 -0400285 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700286 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700287 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400289 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700290 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700291 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700293 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 error = (*filldir)(ent, name, len, file->f_pos,
295 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700296 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 file->f_pos = next;
298 }
299 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700300 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
303int hostfs_file_open(struct inode *ino, struct file *file)
304{
Al Virof8ad8502010-06-06 23:49:18 -0400305 static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400307 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400308 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400309 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700312 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700313 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Al Virof8ad8502010-06-06 23:49:18 -0400315 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Al Virof8ad8502010-06-06 23:49:18 -0400317retry:
318 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400320 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700322 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 r = 1;
324
Al Viroc5322222010-06-06 20:42:10 -0400325 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700326 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700327 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400330 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700331 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700332 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400333
334 mutex_lock(&open_mutex);
335 /* somebody else had handled it first? */
336 if ((mode & HOSTFS_I(ino)->mode) == mode) {
337 mutex_unlock(&open_mutex);
338 return 0;
339 }
340 if ((mode | HOSTFS_I(ino)->mode) != mode) {
341 mode |= HOSTFS_I(ino)->mode;
342 mutex_unlock(&open_mutex);
343 close_file(&fd);
344 goto retry;
345 }
346 if (HOSTFS_I(ino)->fd == -1) {
347 HOSTFS_I(ino)->fd = fd;
348 } else {
349 err = replace_file(fd, HOSTFS_I(ino)->fd);
350 close_file(&fd);
351 if (err < 0) {
352 mutex_unlock(&open_mutex);
353 return err;
354 }
355 }
356 HOSTFS_I(ino)->mode = mode;
357 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Jeff Dikef1adc052007-05-08 00:23:18 -0700359 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200362int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200364 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}
366
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800367static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700369 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200370 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 .aio_read = generic_file_aio_read,
372 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700373 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 .mmap = generic_file_mmap,
375 .open = hostfs_file_open,
376 .release = NULL,
377 .fsync = hostfs_fsync,
378};
379
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800380static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 .llseek = generic_file_llseek,
382 .readdir = hostfs_readdir,
383 .read = generic_read_dir,
384};
385
386int hostfs_writepage(struct page *page, struct writeback_control *wbc)
387{
388 struct address_space *mapping = page->mapping;
389 struct inode *inode = mapping->host;
390 char *buffer;
391 unsigned long long base;
392 int count = PAGE_CACHE_SIZE;
393 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
394 int err;
395
396 if (page->index >= end_index)
397 count = inode->i_size & (PAGE_CACHE_SIZE-1);
398
399 buffer = kmap(page);
400 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
401
402 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700403 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 ClearPageUptodate(page);
405 goto out;
406 }
407
408 if (base > inode->i_size)
409 inode->i_size = base;
410
411 if (PageError(page))
412 ClearPageError(page);
413 err = 0;
414
415 out:
416 kunmap(page);
417
418 unlock_page(page);
419 return err;
420}
421
422int hostfs_readpage(struct file *file, struct page *page)
423{
424 char *buffer;
425 long long start;
426 int err = 0;
427
428 start = (long long) page->index << PAGE_CACHE_SHIFT;
429 buffer = kmap(page);
430 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
431 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700432 if (err < 0)
433 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
436
437 flush_dcache_page(page);
438 SetPageUptodate(page);
439 if (PageError(page)) ClearPageError(page);
440 err = 0;
441 out:
442 kunmap(page);
443 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700444 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
Nick Pigginae361ff2007-10-16 01:25:17 -0700447int hostfs_write_begin(struct file *file, struct address_space *mapping,
448 loff_t pos, unsigned len, unsigned flags,
449 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
Nick Pigginae361ff2007-10-16 01:25:17 -0700451 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Nick Piggin54566b22009-01-04 12:00:53 -0800453 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700454 if (!*pagep)
455 return -ENOMEM;
456 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458
Nick Pigginae361ff2007-10-16 01:25:17 -0700459int hostfs_write_end(struct file *file, struct address_space *mapping,
460 loff_t pos, unsigned len, unsigned copied,
461 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700464 void *buffer;
465 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
466 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700469 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700471
472 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
473 SetPageUptodate(page);
474
Jeff Dike84b3db02007-10-16 01:27:13 -0700475 /*
476 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700477 * i_size against the last byte written.
478 */
479 if (err > 0 && (pos > inode->i_size))
480 inode->i_size = pos;
481 unlock_page(page);
482 page_cache_release(page);
483
Jeff Dikef1adc052007-05-08 00:23:18 -0700484 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485}
486
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700487static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 .writepage = hostfs_writepage,
489 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700490 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700491 .write_begin = hostfs_write_begin,
492 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493};
494
Al Viro4754b822010-06-06 20:33:12 -0400495static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
Al Viro4754b822010-06-06 20:33:12 -0400497 dev_t rdev;
498 struct hostfs_stat st;
499 int err = stat_file(name, &st, -1);
500 if (err)
501 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Al Viro5e2df282010-06-06 19:38:18 -0400503 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400504 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Al Viro4754b822010-06-06 20:33:12 -0400506 switch (st.mode & S_IFMT) {
507 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400508 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400509 break;
510 case S_IFDIR:
511 ino->i_op = &hostfs_dir_iops;
512 ino->i_fop = &hostfs_dir_fops;
513 break;
514 case S_IFCHR:
515 case S_IFBLK:
516 case S_IFIFO:
517 case S_IFSOCK:
518 init_special_inode(ino, st.mode & S_IFMT, rdev);
519 ino->i_op = &hostfs_iops;
520 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Al Viro4754b822010-06-06 20:33:12 -0400522 default:
523 ino->i_op = &hostfs_iops;
524 ino->i_fop = &hostfs_file_fops;
525 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 }
Al Viro4754b822010-06-06 20:33:12 -0400527
528 ino->i_ino = st.ino;
529 ino->i_mode = st.mode;
530 ino->i_nlink = st.nlink;
531 ino->i_uid = st.uid;
532 ino->i_gid = st.gid;
533 ino->i_atime = st.atime;
534 ino->i_mtime = st.mtime;
535 ino->i_ctime = st.ctime;
536 ino->i_size = st.size;
537 ino->i_blocks = st.blocks;
538 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539}
540
541int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700542 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
544 struct inode *inode;
545 char *name;
546 int error, fd;
547
David Howells0a370e52008-02-07 00:15:50 -0800548 inode = hostfs_iget(dir->i_sb);
549 if (IS_ERR(inode)) {
550 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700551 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400555 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700556 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 goto out_put;
558
559 fd = file_create(name,
560 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
561 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
562 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400563 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400565 else
Al Viro5e2df282010-06-06 19:38:18 -0400566 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Al Viroe9193052010-06-06 23:16:34 -0400568 __putname(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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400597 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700598 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 goto out_put;
600
601 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400602
Al Viroe9193052010-06-06 23:16:34 -0400603 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700604 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 iput(inode);
606 inode = NULL;
607 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700608 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 goto out_put;
610
611 d_add(dentry, inode);
612 dentry->d_op = &hostfs_dentry_ops;
Jeff Dikef1adc052007-05-08 00:23:18 -0700613 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 out_put:
616 iput(inode);
617 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700618 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619}
620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
622{
Jeff Dikef1adc052007-05-08 00:23:18 -0700623 char *from_name, *to_name;
624 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
Al Viroc5322222010-06-06 20:42:10 -0400626 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700627 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400628 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700629 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400630 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700631 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700633 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400634 __putname(from_name);
635 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700636 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637}
638
639int hostfs_unlink(struct inode *ino, struct dentry *dentry)
640{
641 char *file;
642 int err;
643
Jeff Dike84b3db02007-10-16 01:27:13 -0700644 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700645 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Al Virof8d7e182010-06-06 23:19:04 -0400647 if ((file = dentry_name(dentry)) == NULL)
648 return -ENOMEM;
649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400651 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700652 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653}
654
655int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
656{
657 char *file;
658 int err;
659
Al Viroc5322222010-06-06 20:42:10 -0400660 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700661 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400663 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700664 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665}
666
667int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
668{
669 char *file;
670 int err;
671
Al Viroc5322222010-06-06 20:42:10 -0400672 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700673 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400675 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700676 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677}
678
679int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
680{
681 char *file;
682 int err;
683
Al Viroc5322222010-06-06 20:42:10 -0400684 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700685 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400687 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689}
690
691int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
692{
693 struct inode *inode;
694 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800695 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
David Howells0a370e52008-02-07 00:15:50 -0800697 inode = hostfs_iget(dir->i_sb);
698 if (IS_ERR(inode)) {
699 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400704 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700705 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 goto out_put;
707
708 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800709 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Al Viroe9193052010-06-06 23:16:34 -0400710 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 goto out_free;
712
713 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400714 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400715 if (err)
716 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700717 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 goto out_put;
719
720 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700721 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400724 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 out_put:
726 iput(inode);
727 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700728 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729}
730
731int hostfs_rename(struct inode *from_ino, struct dentry *from,
732 struct inode *to_ino, struct dentry *to)
733{
734 char *from_name, *to_name;
735 int err;
736
Al Viroc5322222010-06-06 20:42:10 -0400737 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700738 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400739 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400740 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700741 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 }
743 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400744 __putname(from_name);
745 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700746 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747}
748
Al Viroe6305c42008-07-15 21:03:57 -0400749int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750{
751 char *name;
752 int r = 0, w = 0, x = 0, err;
753
754 if (desired & MAY_READ) r = 1;
755 if (desired & MAY_WRITE) w = 1;
756 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400757 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700758 if (name == NULL)
759 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
761 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700762 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 err = 0;
764 else
765 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400766 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700767 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 err = generic_permission(ino, desired, NULL);
769 return err;
770}
771
772int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
773{
Christoph Hellwig10257742010-06-04 11:30:02 +0200774 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 struct hostfs_iattr attrs;
776 char *name;
777 int err;
778
Christoph Hellwig10257742010-06-04 11:30:02 +0200779 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700780
Christoph Hellwig10257742010-06-04 11:30:02 +0200781 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (err)
783 return err;
784
Jeff Dike84b3db02007-10-16 01:27:13 -0700785 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 attr->ia_valid &= ~ATTR_SIZE;
787
788 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700789 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 attrs.ia_valid |= HOSTFS_ATTR_MODE;
791 attrs.ia_mode = attr->ia_mode;
792 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700793 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 attrs.ia_valid |= HOSTFS_ATTR_UID;
795 attrs.ia_uid = attr->ia_uid;
796 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700797 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 attrs.ia_valid |= HOSTFS_ATTR_GID;
799 attrs.ia_gid = attr->ia_gid;
800 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700801 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
803 attrs.ia_size = attr->ia_size;
804 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700805 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
807 attrs.ia_atime = attr->ia_atime;
808 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700809 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
811 attrs.ia_mtime = attr->ia_mtime;
812 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700813 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
815 attrs.ia_ctime = attr->ia_ctime;
816 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700817 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
819 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700820 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
822 }
Al Viroc5322222010-06-06 20:42:10 -0400823 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700824 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700825 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700826 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400827 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700828 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700829 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
Christoph Hellwig10257742010-06-04 11:30:02 +0200831 if ((attr->ia_valid & ATTR_SIZE) &&
832 attr->ia_size != i_size_read(inode)) {
833 int error;
834
835 error = vmtruncate(inode, attr->ia_size);
836 if (err)
837 return err;
838 }
839
840 setattr_copy(inode, attr);
841 mark_inode_dirty(inode);
842 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843}
844
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800845static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 .create = hostfs_create,
847 .link = hostfs_link,
848 .unlink = hostfs_unlink,
849 .symlink = hostfs_symlink,
850 .mkdir = hostfs_mkdir,
851 .rmdir = hostfs_rmdir,
852 .mknod = hostfs_mknod,
853 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 .permission = hostfs_permission,
855 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856};
857
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800858static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 .create = hostfs_create,
860 .lookup = hostfs_lookup,
861 .link = hostfs_link,
862 .unlink = hostfs_unlink,
863 .symlink = hostfs_symlink,
864 .mkdir = hostfs_mkdir,
865 .rmdir = hostfs_rmdir,
866 .mknod = hostfs_mknod,
867 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 .permission = hostfs_permission,
869 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870};
871
Al Virod0352d32010-06-06 21:51:16 -0400872static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873{
Al Virod0352d32010-06-06 21:51:16 -0400874 char *link = __getname();
875 if (link) {
876 char *path = dentry_name(dentry);
877 int err = -ENOMEM;
878 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400879 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400880 if (err == PATH_MAX)
881 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400882 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400883 }
884 if (err < 0) {
885 __putname(link);
886 link = ERR_PTR(err);
887 }
888 } else {
889 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 }
Al Virod0352d32010-06-06 21:51:16 -0400891
892 nd_set_link(nd, link);
893 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894}
895
Al Virod0352d32010-06-06 21:51:16 -0400896static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
897{
898 char *s = nd_get_link(nd);
899 if (!IS_ERR(s))
900 __putname(s);
901}
902
903static const struct inode_operations hostfs_link_iops = {
904 .readlink = generic_readlink,
905 .follow_link = hostfs_follow_link,
906 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907};
908
909static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
910{
911 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700912 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 int err;
914
915 sb->s_blocksize = 1024;
916 sb->s_blocksize_bits = 10;
917 sb->s_magic = HOSTFS_SUPER_MAGIC;
918 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700919 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800921 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700922 if (req_root == NULL)
923 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400926 sb->s_fs_info = host_root_path =
927 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700928 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 goto out;
930
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700931 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Al Viro52b209f72010-06-06 18:43:19 -0400933 root_inode = new_inode(sb);
934 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400935 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Al Viro4754b822010-06-06 20:33:12 -0400937 err = read_name(root_inode, host_root_path);
938 if (err)
939 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400940
Al Viro4754b822010-06-06 20:33:12 -0400941 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f72010-06-06 18:43:19 -0400942 char *name = follow_link(host_root_path);
943 if (IS_ERR(name))
944 err = PTR_ERR(name);
945 else
946 err = read_name(root_inode, name);
947 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400948 if (err)
949 goto out_put;
Al Viro52b209f72010-06-06 18:43:19 -0400950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 err = -ENOMEM;
953 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700954 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 goto out_put;
956
Jeff Dikef1adc052007-05-08 00:23:18 -0700957 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Jeff Dikef1adc052007-05-08 00:23:18 -0700959out_put:
960 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700961out:
962 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963}
964
David Howells454e2392006-06-23 02:02:57 -0700965static int hostfs_read_sb(struct file_system_type *type,
966 int flags, const char *dev_name,
967 void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
David Howells454e2392006-06-23 02:02:57 -0700969 return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970}
971
Al Viro601d2c32010-06-06 17:53:01 -0400972static void hostfs_kill_sb(struct super_block *s)
973{
974 kill_anon_super(s);
975 kfree(s->s_fs_info);
976}
977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978static struct file_system_type hostfs_type = {
979 .owner = THIS_MODULE,
980 .name = "hostfs",
981 .get_sb = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400982 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 .fs_flags = 0,
984};
985
986static int __init init_hostfs(void)
987{
Jeff Dikef1adc052007-05-08 00:23:18 -0700988 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989}
990
991static void __exit exit_hostfs(void)
992{
993 unregister_filesystem(&hostfs_type);
994}
995
996module_init(init_hostfs)
997module_exit(exit_hostfs)
998MODULE_LICENSE("GPL");