blob: 0bc81cf256b8320c325bf64eafd32e1aede575d6 [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
Nick Pigginfe15ce42011-01-07 17:49:23 +110035static int hostfs_d_delete(const 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{
Nick Pigginec2447c2011-01-07 17:49:29 +110095 char *p = dentry_path_raw(dentry, name, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040096 char *root;
97 size_t len;
98
Al Viroe9193052010-06-06 23:16:34 -040099 root = dentry->d_sb->s_fs_info;
100 len = strlen(root);
101 if (IS_ERR(p)) {
102 __putname(name);
103 return NULL;
104 }
Al Viro850a4962010-08-18 06:18:57 -0400105 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -0400106 if (len > p - name) {
107 __putname(name);
108 return NULL;
109 }
110 if (p > name + len) {
111 char *s = name + len;
112 while ((*s++ = *p++) != '\0')
113 ;
114 }
115 return name;
116}
117
Al Viroc5322222010-06-06 20:42:10 -0400118static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119{
Al Viroe9193052010-06-06 23:16:34 -0400120 char *name = __getname();
121 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700122 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Al Viroe9193052010-06-06 23:16:34 -0400124 return __dentry_name(dentry, name); /* will unlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
Al Viroc5322222010-06-06 20:42:10 -0400127static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
129 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100130 char *name;
131
132 dentry = d_find_alias(ino);
133 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400134 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Nick Pigginec2447c2011-01-07 17:49:29 +1100136 name = dentry_name(dentry);
137
138 dput(dentry);
139
140 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141}
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static char *follow_link(char *link)
144{
145 int len, n;
146 char *name, *resolved, *end;
147
148 len = 64;
Jeff Dike84b3db02007-10-16 01:27:13 -0700149 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 n = -ENOMEM;
151 name = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700152 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 goto out;
154
WANG Congea7e7432008-11-19 15:36:46 -0800155 n = hostfs_do_readlink(link, name, len);
Jeff Dike84b3db02007-10-16 01:27:13 -0700156 if (n < len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 break;
158 len *= 2;
159 kfree(name);
160 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700161 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 goto out_free;
163
Jeff Dike84b3db02007-10-16 01:27:13 -0700164 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700165 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700168 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700169 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171 *(end + 1) = '\0';
172 len = strlen(link) + strlen(name) + 1;
173
174 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700175 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 n = -ENOMEM;
177 goto out_free;
178 }
179
180 sprintf(resolved, "%s%s", link, name);
181 kfree(name);
182 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700183 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185 out_free:
186 kfree(name);
187 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700188 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189}
190
David Howells0a370e52008-02-07 00:15:50 -0800191static struct inode *hostfs_iget(struct super_block *sb)
192{
Al Viro52b209f2010-06-06 18:43:19 -0400193 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800194 if (!inode)
195 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800196 return inode;
197}
198
David Howells726c3342006-06-23 02:02:58 -0700199int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
Jeff Dike84b3db02007-10-16 01:27:13 -0700201 /*
202 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 * struct statfs still has 32-bit versions for most of these fields,
204 * so we convert them here
205 */
206 int err;
207 long long f_blocks;
208 long long f_bfree;
209 long long f_bavail;
210 long long f_files;
211 long long f_ffree;
212
Al Viro601d2c32010-06-06 17:53:01 -0400213 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
215 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700216 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700217 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700218 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 sf->f_blocks = f_blocks;
220 sf->f_bfree = f_bfree;
221 sf->f_bavail = f_bavail;
222 sf->f_files = f_files;
223 sf->f_ffree = f_ffree;
224 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700225 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
228static struct inode *hostfs_alloc_inode(struct super_block *sb)
229{
230 struct hostfs_inode_info *hi;
231
Al Viro601d2c32010-06-06 17:53:01 -0400232 hi = kzalloc(sizeof(*hi), GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700233 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700234 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400235 hi->fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 inode_init_once(&hi->vfs_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700237 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
239
Al Viroe971a6d2010-06-06 15:16:17 -0400240static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241{
Mark Fashehfef26652005-09-09 13:01:31 -0700242 truncate_inode_pages(&inode->i_data, 0);
Al Viroe971a6d2010-06-06 15:16:17 -0400243 end_writeback(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700244 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 close_file(&HOSTFS_I(inode)->fd);
246 HOSTFS_I(inode)->fd = -1;
247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
249
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100250static void hostfs_i_callback(struct rcu_head *head)
251{
252 struct inode *inode = container_of(head, struct inode, i_rcu);
253 INIT_LIST_HEAD(&inode->i_dentry);
254 kfree(HOSTFS_I(inode));
255}
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257static void hostfs_destroy_inode(struct inode *inode)
258{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100259 call_rcu(&inode->i_rcu, hostfs_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260}
261
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800262static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
263{
Al Viro601d2c32010-06-06 17:53:01 -0400264 const char *root_path = vfs->mnt_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800265 size_t offset = strlen(root_ino) + 1;
266
267 if (strlen(root_path) > offset)
268 seq_printf(seq, ",%s", root_path + offset);
269
270 return 0;
271}
272
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800273static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400276 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800278 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279};
280
281int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
282{
283 void *dir;
284 char *name;
285 unsigned long long next, ino;
286 int error, len;
287
Al Viroc5322222010-06-06 20:42:10 -0400288 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700289 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700290 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400292 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700293 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700294 return -error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 next = file->f_pos;
Jeff Dike84b3db02007-10-16 01:27:13 -0700296 while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 error = (*filldir)(ent, name, len, file->f_pos,
298 ino, DT_UNKNOWN);
Jeff Dike84b3db02007-10-16 01:27:13 -0700299 if (error) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 file->f_pos = next;
301 }
302 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700303 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304}
305
306int hostfs_file_open(struct inode *ino, struct file *file)
307{
Al Virof8ad8502010-06-06 23:49:18 -0400308 static DEFINE_MUTEX(open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 char *name;
Al Viroaeb5d722008-09-02 15:28:45 -0400310 fmode_t mode = 0;
Al Virof8ad8502010-06-06 23:49:18 -0400311 int err;
Al Viroaeb5d722008-09-02 15:28:45 -0400312 int r = 0, w = 0, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700315 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700316 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Al Virof8ad8502010-06-06 23:49:18 -0400318 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Al Virof8ad8502010-06-06 23:49:18 -0400320retry:
321 if (mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 r = 1;
Al Virof8ad8502010-06-06 23:49:18 -0400323 if (mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 w = 1;
Jeff Dike84b3db02007-10-16 01:27:13 -0700325 if (w)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 r = 1;
327
Al Viroc5322222010-06-06 20:42:10 -0400328 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700329 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700330 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400333 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700334 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700335 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400336
337 mutex_lock(&open_mutex);
338 /* somebody else had handled it first? */
339 if ((mode & HOSTFS_I(ino)->mode) == mode) {
340 mutex_unlock(&open_mutex);
341 return 0;
342 }
343 if ((mode | HOSTFS_I(ino)->mode) != mode) {
344 mode |= HOSTFS_I(ino)->mode;
345 mutex_unlock(&open_mutex);
346 close_file(&fd);
347 goto retry;
348 }
349 if (HOSTFS_I(ino)->fd == -1) {
350 HOSTFS_I(ino)->fd = fd;
351 } else {
352 err = replace_file(fd, HOSTFS_I(ino)->fd);
353 close_file(&fd);
354 if (err < 0) {
355 mutex_unlock(&open_mutex);
356 return err;
357 }
358 }
359 HOSTFS_I(ino)->mode = mode;
360 mutex_unlock(&open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Jeff Dikef1adc052007-05-08 00:23:18 -0700362 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
364
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200365int hostfs_fsync(struct file *file, int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200367 return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
369
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800370static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 .llseek = generic_file_llseek,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700372 .read = do_sync_read,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200373 .splice_read = generic_file_splice_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 .aio_read = generic_file_aio_read,
375 .aio_write = generic_file_aio_write,
Badari Pulavarty543ade12006-09-30 23:28:48 -0700376 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 .mmap = generic_file_mmap,
378 .open = hostfs_file_open,
379 .release = NULL,
380 .fsync = hostfs_fsync,
381};
382
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800383static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 .llseek = generic_file_llseek,
385 .readdir = hostfs_readdir,
386 .read = generic_read_dir,
387};
388
389int hostfs_writepage(struct page *page, struct writeback_control *wbc)
390{
391 struct address_space *mapping = page->mapping;
392 struct inode *inode = mapping->host;
393 char *buffer;
394 unsigned long long base;
395 int count = PAGE_CACHE_SIZE;
396 int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
397 int err;
398
399 if (page->index >= end_index)
400 count = inode->i_size & (PAGE_CACHE_SIZE-1);
401
402 buffer = kmap(page);
403 base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
404
405 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700406 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 ClearPageUptodate(page);
408 goto out;
409 }
410
411 if (base > inode->i_size)
412 inode->i_size = base;
413
414 if (PageError(page))
415 ClearPageError(page);
416 err = 0;
417
418 out:
419 kunmap(page);
420
421 unlock_page(page);
422 return err;
423}
424
425int hostfs_readpage(struct file *file, struct page *page)
426{
427 char *buffer;
428 long long start;
429 int err = 0;
430
431 start = (long long) page->index << PAGE_CACHE_SHIFT;
432 buffer = kmap(page);
433 err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
434 PAGE_CACHE_SIZE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700435 if (err < 0)
436 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
439
440 flush_dcache_page(page);
441 SetPageUptodate(page);
442 if (PageError(page)) ClearPageError(page);
443 err = 0;
444 out:
445 kunmap(page);
446 unlock_page(page);
Jeff Dikef1adc052007-05-08 00:23:18 -0700447 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448}
449
Nick Pigginae361ff2007-10-16 01:25:17 -0700450int hostfs_write_begin(struct file *file, struct address_space *mapping,
451 loff_t pos, unsigned len, unsigned flags,
452 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
Nick Pigginae361ff2007-10-16 01:25:17 -0700454 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Nick Piggin54566b22009-01-04 12:00:53 -0800456 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700457 if (!*pagep)
458 return -ENOMEM;
459 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
Nick Pigginae361ff2007-10-16 01:25:17 -0700462int hostfs_write_end(struct file *file, struct address_space *mapping,
463 loff_t pos, unsigned len, unsigned copied,
464 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700467 void *buffer;
468 unsigned from = pos & (PAGE_CACHE_SIZE - 1);
469 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700472 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700474
475 if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
476 SetPageUptodate(page);
477
Jeff Dike84b3db02007-10-16 01:27:13 -0700478 /*
479 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700480 * i_size against the last byte written.
481 */
482 if (err > 0 && (pos > inode->i_size))
483 inode->i_size = pos;
484 unlock_page(page);
485 page_cache_release(page);
486
Jeff Dikef1adc052007-05-08 00:23:18 -0700487 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700490static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 .writepage = hostfs_writepage,
492 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700493 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700494 .write_begin = hostfs_write_begin,
495 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496};
497
Al Viro4754b822010-06-06 20:33:12 -0400498static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Al Viro4754b822010-06-06 20:33:12 -0400500 dev_t rdev;
501 struct hostfs_stat st;
502 int err = stat_file(name, &st, -1);
503 if (err)
504 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Al Viro5e2df282010-06-06 19:38:18 -0400506 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400507 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Al Viro4754b822010-06-06 20:33:12 -0400509 switch (st.mode & S_IFMT) {
510 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400511 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400512 break;
513 case S_IFDIR:
514 ino->i_op = &hostfs_dir_iops;
515 ino->i_fop = &hostfs_dir_fops;
516 break;
517 case S_IFCHR:
518 case S_IFBLK:
519 case S_IFIFO:
520 case S_IFSOCK:
521 init_special_inode(ino, st.mode & S_IFMT, rdev);
522 ino->i_op = &hostfs_iops;
523 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Al Viro4754b822010-06-06 20:33:12 -0400525 default:
526 ino->i_op = &hostfs_iops;
527 ino->i_fop = &hostfs_file_fops;
528 ino->i_mapping->a_ops = &hostfs_aops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
Al Viro4754b822010-06-06 20:33:12 -0400530
531 ino->i_ino = st.ino;
532 ino->i_mode = st.mode;
533 ino->i_nlink = st.nlink;
534 ino->i_uid = st.uid;
535 ino->i_gid = st.gid;
536 ino->i_atime = st.atime;
537 ino->i_mtime = st.mtime;
538 ino->i_ctime = st.ctime;
539 ino->i_size = st.size;
540 ino->i_blocks = st.blocks;
541 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542}
543
544int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
Jeff Dike84b3db02007-10-16 01:27:13 -0700545 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 struct inode *inode;
548 char *name;
549 int error, fd;
550
David Howells0a370e52008-02-07 00:15:50 -0800551 inode = hostfs_iget(dir->i_sb);
552 if (IS_ERR(inode)) {
553 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700554 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400558 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700559 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 goto out_put;
561
562 fd = file_create(name,
563 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
564 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
565 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
Al Viro4754b822010-06-06 20:33:12 -0400566 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400568 else
Al Viro5e2df282010-06-06 19:38:18 -0400569 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Al Viroe9193052010-06-06 23:16:34 -0400571 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700572 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 goto out_put;
574
575 HOSTFS_I(inode)->fd = fd;
576 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
577 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700578 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580 out_put:
581 iput(inode);
582 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700583 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
586struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
Jeff Dikef1adc052007-05-08 00:23:18 -0700587 struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
589 struct inode *inode;
590 char *name;
591 int err;
592
David Howells0a370e52008-02-07 00:15:50 -0800593 inode = hostfs_iget(ino->i_sb);
594 if (IS_ERR(inode)) {
595 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400600 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700601 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 goto out_put;
603
604 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400605
Al Viroe9193052010-06-06 23:16:34 -0400606 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700607 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 iput(inode);
609 inode = NULL;
610 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700611 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto out_put;
613
614 d_add(dentry, inode);
Nick Pigginfb045ad2011-01-07 17:49:55 +1100615 d_set_d_op(dentry, &hostfs_dentry_ops);
Jeff Dikef1adc052007-05-08 00:23:18 -0700616 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 out_put:
619 iput(inode);
620 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700621 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622}
623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
625{
Jeff Dikef1adc052007-05-08 00:23:18 -0700626 char *from_name, *to_name;
627 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Al Viroc5322222010-06-06 20:42:10 -0400629 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700630 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400631 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700632 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400633 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700634 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700636 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400637 __putname(from_name);
638 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
642int hostfs_unlink(struct inode *ino, struct dentry *dentry)
643{
644 char *file;
645 int err;
646
Jeff Dike84b3db02007-10-16 01:27:13 -0700647 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700648 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Al Virof8d7e182010-06-06 23:19:04 -0400650 if ((file = dentry_name(dentry)) == NULL)
651 return -ENOMEM;
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400654 __putname(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
Al Viroc5322222010-06-06 20:42:10 -0400663 if ((file = dentry_name(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);
Al Viroe9193052010-06-06 23:16:34 -0400666 __putname(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
Al Viroc5322222010-06-06 20:42:10 -0400675 if ((file = dentry_name(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);
Al Viroe9193052010-06-06 23:16:34 -0400678 __putname(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
Al Viroc5322222010-06-06 20:42:10 -0400687 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700688 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400690 __putname(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;
Al Viroc5322222010-06-06 20:42:10 -0400707 name = dentry_name(dentry);
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));
Al Viroe9193052010-06-06 23:16:34 -0400713 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 goto out_free;
715
716 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400717 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400718 if (err)
719 goto out_put;
Jeff Dike84b3db02007-10-16 01:27:13 -0700720 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 goto out_put;
722
723 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700724 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400727 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 out_put:
729 iput(inode);
730 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700731 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
733
734int hostfs_rename(struct inode *from_ino, struct dentry *from,
735 struct inode *to_ino, struct dentry *to)
736{
737 char *from_name, *to_name;
738 int err;
739
Al Viroc5322222010-06-06 20:42:10 -0400740 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700741 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400742 if ((to_name = dentry_name(to)) == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400743 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700744 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 }
746 err = rename_file(from_name, to_name);
Al Viroe9193052010-06-06 23:16:34 -0400747 __putname(from_name);
748 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700749 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750}
751
Al Viroe6305c42008-07-15 21:03:57 -0400752int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
754 char *name;
755 int r = 0, w = 0, x = 0, err;
756
757 if (desired & MAY_READ) r = 1;
758 if (desired & MAY_WRITE) w = 1;
759 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400760 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700761 if (name == NULL)
762 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700765 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 err = 0;
767 else
768 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400769 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700770 if (!err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 err = generic_permission(ino, desired, NULL);
772 return err;
773}
774
775int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
776{
Christoph Hellwig10257742010-06-04 11:30:02 +0200777 struct inode *inode = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 struct hostfs_iattr attrs;
779 char *name;
780 int err;
781
Christoph Hellwig10257742010-06-04 11:30:02 +0200782 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700783
Christoph Hellwig10257742010-06-04 11:30:02 +0200784 err = inode_change_ok(inode, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 if (err)
786 return err;
787
Jeff Dike84b3db02007-10-16 01:27:13 -0700788 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 attr->ia_valid &= ~ATTR_SIZE;
790
791 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700792 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 attrs.ia_valid |= HOSTFS_ATTR_MODE;
794 attrs.ia_mode = attr->ia_mode;
795 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700796 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 attrs.ia_valid |= HOSTFS_ATTR_UID;
798 attrs.ia_uid = attr->ia_uid;
799 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700800 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 attrs.ia_valid |= HOSTFS_ATTR_GID;
802 attrs.ia_gid = attr->ia_gid;
803 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700804 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
806 attrs.ia_size = attr->ia_size;
807 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700808 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
810 attrs.ia_atime = attr->ia_atime;
811 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700812 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
814 attrs.ia_mtime = attr->ia_mtime;
815 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700816 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
818 attrs.ia_ctime = attr->ia_ctime;
819 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700820 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
822 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700823 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
825 }
Al Viroc5322222010-06-06 20:42:10 -0400826 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700827 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700828 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700829 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400830 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700831 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700832 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Christoph Hellwig10257742010-06-04 11:30:02 +0200834 if ((attr->ia_valid & ATTR_SIZE) &&
835 attr->ia_size != i_size_read(inode)) {
836 int error;
837
838 error = vmtruncate(inode, attr->ia_size);
839 if (err)
840 return err;
841 }
842
843 setattr_copy(inode, attr);
844 mark_inode_dirty(inode);
845 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846}
847
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800848static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 .create = hostfs_create,
850 .link = hostfs_link,
851 .unlink = hostfs_unlink,
852 .symlink = hostfs_symlink,
853 .mkdir = hostfs_mkdir,
854 .rmdir = hostfs_rmdir,
855 .mknod = hostfs_mknod,
856 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 .permission = hostfs_permission,
858 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859};
860
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800861static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 .create = hostfs_create,
863 .lookup = hostfs_lookup,
864 .link = hostfs_link,
865 .unlink = hostfs_unlink,
866 .symlink = hostfs_symlink,
867 .mkdir = hostfs_mkdir,
868 .rmdir = hostfs_rmdir,
869 .mknod = hostfs_mknod,
870 .rename = hostfs_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 .permission = hostfs_permission,
872 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873};
874
Al Virod0352d32010-06-06 21:51:16 -0400875static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
Al Virod0352d32010-06-06 21:51:16 -0400877 char *link = __getname();
878 if (link) {
879 char *path = dentry_name(dentry);
880 int err = -ENOMEM;
881 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400882 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400883 if (err == PATH_MAX)
884 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400885 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400886 }
887 if (err < 0) {
888 __putname(link);
889 link = ERR_PTR(err);
890 }
891 } else {
892 link = ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 }
Al Virod0352d32010-06-06 21:51:16 -0400894
895 nd_set_link(nd, link);
896 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897}
898
Al Virod0352d32010-06-06 21:51:16 -0400899static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
900{
901 char *s = nd_get_link(nd);
902 if (!IS_ERR(s))
903 __putname(s);
904}
905
906static const struct inode_operations hostfs_link_iops = {
907 .readlink = generic_readlink,
908 .follow_link = hostfs_follow_link,
909 .put_link = hostfs_put_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910};
911
912static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
913{
914 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700915 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 int err;
917
918 sb->s_blocksize = 1024;
919 sb->s_blocksize_bits = 10;
920 sb->s_magic = HOSTFS_SUPER_MAGIC;
921 sb->s_op = &hostfs_sbops;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700922 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800924 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700925 if (req_root == NULL)
926 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400929 sb->s_fs_info = host_root_path =
930 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700931 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 goto out;
933
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700934 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Al Viro52b209f2010-06-06 18:43:19 -0400936 root_inode = new_inode(sb);
937 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400938 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Al Viro4754b822010-06-06 20:33:12 -0400940 err = read_name(root_inode, host_root_path);
941 if (err)
942 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400943
Al Viro4754b822010-06-06 20:33:12 -0400944 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400945 char *name = follow_link(host_root_path);
946 if (IS_ERR(name))
947 err = PTR_ERR(name);
948 else
949 err = read_name(root_inode, name);
950 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400951 if (err)
952 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 err = -ENOMEM;
956 sb->s_root = d_alloc_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700957 if (sb->s_root == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 goto out_put;
959
Jeff Dikef1adc052007-05-08 00:23:18 -0700960 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Jeff Dikef1adc052007-05-08 00:23:18 -0700962out_put:
963 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700964out:
965 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
Al Viro3c26ff62010-07-25 11:46:36 +0400968static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700969 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400970 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
Al Viro3c26ff62010-07-25 11:46:36 +0400972 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973}
974
Al Viro601d2c32010-06-06 17:53:01 -0400975static void hostfs_kill_sb(struct super_block *s)
976{
977 kill_anon_super(s);
978 kfree(s->s_fs_info);
979}
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981static struct file_system_type hostfs_type = {
982 .owner = THIS_MODULE,
983 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +0400984 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -0400985 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 .fs_flags = 0,
987};
988
989static int __init init_hostfs(void)
990{
Jeff Dikef1adc052007-05-08 00:23:18 -0700991 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992}
993
994static void __exit exit_hostfs(void)
995{
996 unregister_filesystem(&hostfs_type);
997}
998
999module_init(init_hostfs)
1000module_exit(exit_hostfs)
1001MODULE_LICENSE("GPL");