blob: e61261a7417e57cc49a784c5a54b8a15f92bd352 [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>
James Hogan2b3b9bb2013-03-27 10:47:13 +000010#include <linux/magic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/module.h>
Jeff Dike84b3db02007-10-16 01:27:13 -070012#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/statfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090015#include <linux/slab.h>
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -080016#include <linux/seq_file.h>
Jiri Kosina6966a972008-02-09 00:10:14 -080017#include <linux/mount.h>
Al Virod0352d32010-06-06 21:51:16 -040018#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include "hostfs.h"
Al Viro37185b32012-10-08 03:27:32 +010020#include <init.h>
21#include <kern.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
23struct hostfs_inode_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 int fd;
Al Viroaeb5d722008-09-02 15:28:45 -040025 fmode_t mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 struct inode vfs_inode;
Richard Weinberger69886e62015-02-27 22:55:20 +010027 struct mutex open_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -070028};
29
30static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
31{
Jeff Dikef1adc052007-05-08 00:23:18 -070032 return list_entry(inode, struct hostfs_inode_info, vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070033}
34
Al Viro496ad9a2013-01-23 17:07:38 -050035#define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file))
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037/* Changed in hostfs_args before the kernel starts running */
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -080038static char *root_ino = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070039static int append = 0;
40
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080041static const struct inode_operations hostfs_iops;
42static const struct inode_operations hostfs_dir_iops;
Al Virod0352d32010-06-06 21:51:16 -040043static const struct inode_operations hostfs_link_iops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45#ifndef MODULE
46static int __init hostfs_args(char *options, int *add)
47{
48 char *ptr;
49
50 ptr = strchr(options, ',');
Jeff Dike84b3db02007-10-16 01:27:13 -070051 if (ptr != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 *ptr++ = '\0';
Jeff Dike84b3db02007-10-16 01:27:13 -070053 if (*options != '\0')
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 root_ino = options;
55
56 options = ptr;
Jeff Dike84b3db02007-10-16 01:27:13 -070057 while (options) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 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') {
62 if (!strcmp(options, "append"))
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 append = 1;
64 else printf("hostfs_args - unsupported option - %s\n",
65 options);
66 }
67 options = ptr;
68 }
Jeff Dikef1adc052007-05-08 00:23:18 -070069 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
71
72__uml_setup("hostfs=", hostfs_args,
73"hostfs=<root dir>,<flags>,...\n"
74" This is used to set hostfs parameters. The root directory argument\n"
75" is used to confine all hostfs mounts to within the specified directory\n"
76" tree on the host. If this isn't specified, then a user inside UML can\n"
77" mount anything on the host that's accessible to the user that's running\n"
78" it.\n"
79" The only flag currently supported is 'append', which specifies that all\n"
80" files opened by hostfs will be opened in append mode.\n\n"
81);
82#endif
83
Al Viroe9193052010-06-06 23:16:34 -040084static char *__dentry_name(struct dentry *dentry, char *name)
85{
Nick Pigginec2447c2011-01-07 17:49:29 +110086 char *p = dentry_path_raw(dentry, name, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -040087 char *root;
88 size_t len;
89
Al Viroe9193052010-06-06 23:16:34 -040090 root = dentry->d_sb->s_fs_info;
91 len = strlen(root);
92 if (IS_ERR(p)) {
93 __putname(name);
94 return NULL;
95 }
Richard Weinbergeraad50b12015-03-03 23:41:52 +010096
97 /*
98 * This function relies on the fact that dentry_path_raw() will place
99 * the path name at the end of the provided buffer.
100 */
101 BUG_ON(p + strlen(p) + 1 != name + PATH_MAX);
102
Al Viro850a4962010-08-18 06:18:57 -0400103 strlcpy(name, root, PATH_MAX);
Al Viroe9193052010-06-06 23:16:34 -0400104 if (len > p - name) {
105 __putname(name);
106 return NULL;
107 }
Richard Weinbergerc278e812015-03-03 23:42:25 +0100108
109 if (p > name + len)
110 strcpy(name + len, p);
111
Al Viroe9193052010-06-06 23:16:34 -0400112 return name;
113}
114
Al Viroc5322222010-06-06 20:42:10 -0400115static char *dentry_name(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
Al Viroe9193052010-06-06 23:16:34 -0400117 char *name = __getname();
118 if (!name)
Jeff Dikef1adc052007-05-08 00:23:18 -0700119 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
James Hogan9dcc5e82013-03-27 10:47:12 +0000121 return __dentry_name(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
Al Viroc5322222010-06-06 20:42:10 -0400124static char *inode_name(struct inode *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
126 struct dentry *dentry;
Nick Pigginec2447c2011-01-07 17:49:29 +1100127 char *name;
128
129 dentry = d_find_alias(ino);
130 if (!dentry)
Al Viroe9193052010-06-06 23:16:34 -0400131 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Nick Pigginec2447c2011-01-07 17:49:29 +1100133 name = dentry_name(dentry);
134
135 dput(dentry);
136
137 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140static char *follow_link(char *link)
141{
142 int len, n;
143 char *name, *resolved, *end;
144
Richard Weinberger7c950992015-03-03 23:55:49 +0100145 name = __getname();
146 if (!name) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 n = -ENOMEM;
Richard Weinberger7c950992015-03-03 23:55:49 +0100148 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 }
Richard Weinberger7c950992015-03-03 23:55:49 +0100150
151 n = hostfs_do_readlink(link, name, PATH_MAX);
Jeff Dike84b3db02007-10-16 01:27:13 -0700152 if (n < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 goto out_free;
Richard Weinberger7c950992015-03-03 23:55:49 +0100154 else if (n == PATH_MAX) {
155 n = -E2BIG;
156 goto out_free;
157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Jeff Dike84b3db02007-10-16 01:27:13 -0700159 if (*name == '/')
Jeff Dikef1adc052007-05-08 00:23:18 -0700160 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162 end = strrchr(link, '/');
Jeff Dike84b3db02007-10-16 01:27:13 -0700163 if (end == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700164 return name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166 *(end + 1) = '\0';
167 len = strlen(link) + strlen(name) + 1;
168
169 resolved = kmalloc(len, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700170 if (resolved == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 n = -ENOMEM;
172 goto out_free;
173 }
174
175 sprintf(resolved, "%s%s", link, name);
Richard Weinberger7c950992015-03-03 23:55:49 +0100176 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 kfree(link);
Jeff Dikef1adc052007-05-08 00:23:18 -0700178 return resolved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180 out_free:
Richard Weinberger7c950992015-03-03 23:55:49 +0100181 __putname(name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700182 return ERR_PTR(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183}
184
David Howells0a370e52008-02-07 00:15:50 -0800185static struct inode *hostfs_iget(struct super_block *sb)
186{
Al Viro52b209f2010-06-06 18:43:19 -0400187 struct inode *inode = new_inode(sb);
David Howells0a370e52008-02-07 00:15:50 -0800188 if (!inode)
189 return ERR_PTR(-ENOMEM);
David Howells0a370e52008-02-07 00:15:50 -0800190 return inode;
191}
192
James Hogan9e443bc2013-11-14 21:15:13 +0000193static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194{
Jeff Dike84b3db02007-10-16 01:27:13 -0700195 /*
196 * do_statfs uses struct statfs64 internally, but the linux kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 * struct statfs still has 32-bit versions for most of these fields,
198 * so we convert them here
199 */
200 int err;
201 long long f_blocks;
202 long long f_bfree;
203 long long f_bavail;
204 long long f_files;
205 long long f_ffree;
206
Al Viro601d2c32010-06-06 17:53:01 -0400207 err = do_statfs(dentry->d_sb->s_fs_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
209 &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
Richard Weinberger1b627d52010-10-26 14:21:18 -0700210 &sf->f_namelen);
Jeff Dike84b3db02007-10-16 01:27:13 -0700211 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700212 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 sf->f_blocks = f_blocks;
214 sf->f_bfree = f_bfree;
215 sf->f_bavail = f_bavail;
216 sf->f_files = f_files;
217 sf->f_ffree = f_ffree;
218 sf->f_type = HOSTFS_SUPER_MAGIC;
Jeff Dikef1adc052007-05-08 00:23:18 -0700219 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220}
221
222static struct inode *hostfs_alloc_inode(struct super_block *sb)
223{
224 struct hostfs_inode_info *hi;
225
Vladimir Davydov5d097052016-01-14 15:18:21 -0800226 hi = kmalloc(sizeof(*hi), GFP_KERNEL_ACCOUNT);
Jeff Dike84b3db02007-10-16 01:27:13 -0700227 if (hi == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700228 return NULL;
Al Viro601d2c32010-06-06 17:53:01 -0400229 hi->fd = -1;
James Hogan371fdab2013-03-27 10:47:14 +0000230 hi->mode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 inode_init_once(&hi->vfs_inode);
Richard Weinberger69886e62015-02-27 22:55:20 +0100232 mutex_init(&hi->open_mutex);
Jeff Dikef1adc052007-05-08 00:23:18 -0700233 return &hi->vfs_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234}
235
Al Viroe971a6d2010-06-06 15:16:17 -0400236static void hostfs_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
Johannes Weiner91b0abe2014-04-03 14:47:49 -0700238 truncate_inode_pages_final(&inode->i_data);
Jan Karadbd57682012-05-03 14:48:02 +0200239 clear_inode(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700240 if (HOSTFS_I(inode)->fd != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 close_file(&HOSTFS_I(inode)->fd);
242 HOSTFS_I(inode)->fd = -1;
243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244}
245
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100246static void hostfs_i_callback(struct rcu_head *head)
247{
248 struct inode *inode = container_of(head, struct inode, i_rcu);
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100249 kfree(HOSTFS_I(inode));
250}
251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252static void hostfs_destroy_inode(struct inode *inode)
253{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +1100254 call_rcu(&inode->i_rcu, hostfs_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255}
256
Al Viro34c80b12011-12-08 21:32:45 -0500257static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800258{
Al Viro34c80b12011-12-08 21:32:45 -0500259 const char *root_path = root->d_sb->s_fs_info;
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800260 size_t offset = strlen(root_ino) + 1;
261
262 if (strlen(root_path) > offset)
Kees Cooka068acf2015-09-04 15:44:57 -0700263 seq_show_option(seq, root_path + offset, NULL);
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800264
Richard Weinberger7f74a662015-03-04 00:00:54 +0100265 if (append)
266 seq_puts(seq, ",append");
267
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800268 return 0;
269}
270
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800271static const struct super_operations hostfs_sbops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 .alloc_inode = hostfs_alloc_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 .destroy_inode = hostfs_destroy_inode,
Al Viroe971a6d2010-06-06 15:16:17 -0400274 .evict_inode = hostfs_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 .statfs = hostfs_statfs,
Miklos Szeredidd2cc4d2008-02-08 04:21:43 -0800276 .show_options = hostfs_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277};
278
James Hogan9e443bc2013-11-14 21:15:13 +0000279static int hostfs_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280{
281 void *dir;
282 char *name;
283 unsigned long long next, ino;
284 int error, len;
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100285 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Al Viroc5322222010-06-06 20:42:10 -0400287 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700288 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700289 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 dir = open_dir(name, &error);
Al Viroe9193052010-06-06 23:16:34 -0400291 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700292 if (dir == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700293 return -error;
Al Viro8e28bc72013-05-22 16:34:19 -0400294 next = ctx->pos;
Richard Weinberger0c9bd632015-03-24 15:47:38 +0100295 seek_dir(dir, next);
Geert Uytterhoeven3ee6bd82012-01-27 19:14:58 +0100296 while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
Al Viro8e28bc72013-05-22 16:34:19 -0400297 if (!dir_emit(ctx, name, len, ino, type))
298 break;
299 ctx->pos = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301 close_dir(dir);
Jeff Dikef1adc052007-05-08 00:23:18 -0700302 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303}
304
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100305static int hostfs_open(struct inode *ino, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
307 char *name;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100308 fmode_t mode;
Al Virof8ad8502010-06-06 23:49:18 -0400309 int err;
Richard Weinbergerbd1052a2015-03-04 00:06:38 +0100310 int r, w, fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
Jeff Dike84b3db02007-10-16 01:27:13 -0700313 if ((mode & HOSTFS_I(ino)->mode) == mode)
Jeff Dikef1adc052007-05-08 00:23:18 -0700314 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Al Virof8ad8502010-06-06 23:49:18 -0400316 mode |= HOSTFS_I(ino)->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Al Virof8ad8502010-06-06 23:49:18 -0400318retry:
Richard Weinbergera9d19582015-03-04 22:39:48 +0100319 r = w = 0;
320
Al Virof8ad8502010-06-06 23:49:18 -0400321 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)
Richard Weinberger112a5da2015-03-04 00:05:11 +0100324 r = w = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Al Viroc5322222010-06-06 20:42:10 -0400326 name = dentry_name(file->f_path.dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700327 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700328 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 fd = open_file(name, r, w, append);
Al Viroe9193052010-06-06 23:16:34 -0400331 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700332 if (fd < 0)
Jeff Dikef1adc052007-05-08 00:23:18 -0700333 return fd;
Al Virof8ad8502010-06-06 23:49:18 -0400334
Richard Weinberger69886e62015-02-27 22:55:20 +0100335 mutex_lock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400336 /* somebody else had handled it first? */
337 if ((mode & HOSTFS_I(ino)->mode) == mode) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100338 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Richard Weinbergeraf955652015-02-27 22:56:28 +0100339 close_file(&fd);
Al Virof8ad8502010-06-06 23:49:18 -0400340 return 0;
341 }
342 if ((mode | HOSTFS_I(ino)->mode) != mode) {
343 mode |= HOSTFS_I(ino)->mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100344 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400345 close_file(&fd);
346 goto retry;
347 }
348 if (HOSTFS_I(ino)->fd == -1) {
349 HOSTFS_I(ino)->fd = fd;
350 } else {
351 err = replace_file(fd, HOSTFS_I(ino)->fd);
352 close_file(&fd);
353 if (err < 0) {
Richard Weinberger69886e62015-02-27 22:55:20 +0100354 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Al Virof8ad8502010-06-06 23:49:18 -0400355 return err;
356 }
357 }
358 HOSTFS_I(ino)->mode = mode;
Richard Weinberger69886e62015-02-27 22:55:20 +0100359 mutex_unlock(&HOSTFS_I(ino)->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Jeff Dikef1adc052007-05-08 00:23:18 -0700361 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
Richard Weinberger65984ff2013-08-04 17:23:51 +0000364static int hostfs_file_release(struct inode *inode, struct file *file)
365{
366 filemap_write_and_wait(inode->i_mapping);
367
368 return 0;
369}
370
James Hogan9e443bc2013-11-14 21:15:13 +0000371static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
372 int datasync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
Josef Bacik02c24a82011-07-16 20:44:56 -0400374 struct inode *inode = file->f_mapping->host;
375 int ret;
376
377 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
378 if (ret)
379 return ret;
380
Al Viro59551022016-01-22 15:40:57 -0500381 inode_lock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400382 ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
Al Viro59551022016-01-22 15:40:57 -0500383 inode_unlock(inode);
Josef Bacik02c24a82011-07-16 20:44:56 -0400384
385 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386}
387
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800388static const struct file_operations hostfs_file_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 .llseek = generic_file_llseek,
Jens Axboe5ffc4ef2007-06-01 11:49:19 +0200390 .splice_read = generic_file_splice_read,
Al Viroaad4f8b2014-04-02 14:33:16 -0400391 .read_iter = generic_file_read_iter,
Al Viro81742022014-04-03 03:17:43 -0400392 .write_iter = generic_file_write_iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 .mmap = generic_file_mmap,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100394 .open = hostfs_open,
Richard Weinberger65984ff2013-08-04 17:23:51 +0000395 .release = hostfs_file_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 .fsync = hostfs_fsync,
397};
398
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800399static const struct file_operations hostfs_dir_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 .llseek = generic_file_llseek,
Al Viro552a9d42016-05-12 19:49:30 -0400401 .iterate_shared = hostfs_readdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 .read = generic_read_dir,
Richard Weinberger4c6dcaf2015-03-02 00:09:33 +0100403 .open = hostfs_open,
404 .fsync = hostfs_fsync,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405};
406
James Hogan9e443bc2013-11-14 21:15:13 +0000407static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 struct address_space *mapping = page->mapping;
410 struct inode *inode = mapping->host;
411 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100412 loff_t base = page_offset(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300413 int count = PAGE_SIZE;
414 int end_index = inode->i_size >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 int err;
416
417 if (page->index >= end_index)
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300418 count = inode->i_size & (PAGE_SIZE-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
420 buffer = kmap(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
422 err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
Jeff Dike84b3db02007-10-16 01:27:13 -0700423 if (err != count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 ClearPageUptodate(page);
425 goto out;
426 }
427
428 if (base > inode->i_size)
429 inode->i_size = base;
430
431 if (PageError(page))
432 ClearPageError(page);
433 err = 0;
434
435 out:
436 kunmap(page);
437
438 unlock_page(page);
439 return err;
440}
441
James Hogan9e443bc2013-11-14 21:15:13 +0000442static int hostfs_readpage(struct file *file, struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
444 char *buffer;
Richard Weinbergeraf6aa1b92015-03-04 20:58:39 +0100445 loff_t start = page_offset(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100446 int bytes_read, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 buffer = kmap(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100449 bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300450 PAGE_SIZE);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100451 if (bytes_read < 0) {
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100452 ClearPageUptodate(page);
453 SetPageError(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100454 ret = bytes_read;
Jeff Dike84b3db02007-10-16 01:27:13 -0700455 goto out;
Richard Weinberger41761dd2015-03-03 21:40:55 +0100456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300458 memset(buffer + bytes_read, 0, PAGE_SIZE - bytes_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100460 ClearPageError(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 SetPageUptodate(page);
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 out:
Richard Weinbergerb86b4132015-03-04 12:44:03 +0100464 flush_dcache_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 kunmap(page);
466 unlock_page(page);
Richard Weinberger41761dd2015-03-03 21:40:55 +0100467 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
James Hogan9e443bc2013-11-14 21:15:13 +0000470static int hostfs_write_begin(struct file *file, struct address_space *mapping,
471 loff_t pos, unsigned len, unsigned flags,
472 struct page **pagep, void **fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300474 pgoff_t index = pos >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Nick Piggin54566b22009-01-04 12:00:53 -0800476 *pagep = grab_cache_page_write_begin(mapping, index, flags);
Nick Pigginae361ff2007-10-16 01:25:17 -0700477 if (!*pagep)
478 return -ENOMEM;
479 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480}
481
James Hogan9e443bc2013-11-14 21:15:13 +0000482static int hostfs_write_end(struct file *file, struct address_space *mapping,
483 loff_t pos, unsigned len, unsigned copied,
484 struct page *page, void *fsdata)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 struct inode *inode = mapping->host;
Nick Pigginae361ff2007-10-16 01:25:17 -0700487 void *buffer;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300488 unsigned from = pos & (PAGE_SIZE - 1);
Nick Pigginae361ff2007-10-16 01:25:17 -0700489 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 buffer = kmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700492 err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 kunmap(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700494
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300495 if (!PageUptodate(page) && err == PAGE_SIZE)
Nick Pigginae361ff2007-10-16 01:25:17 -0700496 SetPageUptodate(page);
497
Jeff Dike84b3db02007-10-16 01:27:13 -0700498 /*
499 * If err > 0, write_file has added err to pos, so we are comparing
Nick Pigginae361ff2007-10-16 01:25:17 -0700500 * i_size against the last byte written.
501 */
502 if (err > 0 && (pos > inode->i_size))
503 inode->i_size = pos;
504 unlock_page(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300505 put_page(page);
Nick Pigginae361ff2007-10-16 01:25:17 -0700506
Jeff Dikef1adc052007-05-08 00:23:18 -0700507 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
Christoph Hellwigf5e54d62006-06-28 04:26:44 -0700510static const struct address_space_operations hostfs_aops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 .writepage = hostfs_writepage,
512 .readpage = hostfs_readpage,
Paolo 'Blaisorblade' Giarrussoffa0aea2005-05-01 08:58:56 -0700513 .set_page_dirty = __set_page_dirty_nobuffers,
Nick Pigginae361ff2007-10-16 01:25:17 -0700514 .write_begin = hostfs_write_begin,
515 .write_end = hostfs_write_end,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516};
517
Al Viro4754b822010-06-06 20:33:12 -0400518static int read_name(struct inode *ino, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
Al Viro4754b822010-06-06 20:33:12 -0400520 dev_t rdev;
521 struct hostfs_stat st;
522 int err = stat_file(name, &st, -1);
523 if (err)
524 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Al Viro5e2df282010-06-06 19:38:18 -0400526 /* Reencode maj and min with the kernel encoding.*/
Al Viro4754b822010-06-06 20:33:12 -0400527 rdev = MKDEV(st.maj, st.min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Al Viro4754b822010-06-06 20:33:12 -0400529 switch (st.mode & S_IFMT) {
530 case S_IFLNK:
Al Virod0352d32010-06-06 21:51:16 -0400531 ino->i_op = &hostfs_link_iops;
Al Viro4754b822010-06-06 20:33:12 -0400532 break;
533 case S_IFDIR:
534 ino->i_op = &hostfs_dir_iops;
535 ino->i_fop = &hostfs_dir_fops;
536 break;
537 case S_IFCHR:
538 case S_IFBLK:
539 case S_IFIFO:
540 case S_IFSOCK:
541 init_special_inode(ino, st.mode & S_IFMT, rdev);
542 ino->i_op = &hostfs_iops;
543 break;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100544 case S_IFREG:
Al Viro4754b822010-06-06 20:33:12 -0400545 ino->i_op = &hostfs_iops;
546 ino->i_fop = &hostfs_file_fops;
547 ino->i_mapping->a_ops = &hostfs_aops;
Richard Weinberger2ad2dca2015-03-02 00:10:25 +0100548 break;
549 default:
550 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 }
Al Viro4754b822010-06-06 20:33:12 -0400552
553 ino->i_ino = st.ino;
554 ino->i_mode = st.mode;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200555 set_nlink(ino, st.nlink);
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800556 i_uid_write(ino, st.uid);
557 i_gid_write(ino, st.gid);
Al Viro4754b822010-06-06 20:33:12 -0400558 ino->i_atime = st.atime;
559 ino->i_mtime = st.mtime;
560 ino->i_ctime = st.ctime;
561 ino->i_size = st.size;
562 ino->i_blocks = st.blocks;
563 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564}
565
James Hogan9e443bc2013-11-14 21:15:13 +0000566static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
567 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
569 struct inode *inode;
570 char *name;
571 int error, fd;
572
David Howells0a370e52008-02-07 00:15:50 -0800573 inode = hostfs_iget(dir->i_sb);
574 if (IS_ERR(inode)) {
575 error = PTR_ERR(inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700576 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 error = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400580 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700581 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 goto out_put;
583
Richard Weinbergera718c922015-05-04 14:50:29 +0200584 fd = file_create(name, mode & 0777);
Al Viro4754b822010-06-06 20:33:12 -0400585 if (fd < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 error = fd;
Al Viro4754b822010-06-06 20:33:12 -0400587 else
Al Viro5e2df282010-06-06 19:38:18 -0400588 error = read_name(inode, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Al Viroe9193052010-06-06 23:16:34 -0400590 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700591 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 goto out_put;
593
594 HOSTFS_I(inode)->fd = fd;
595 HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
596 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700597 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 out_put:
600 iput(inode);
601 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700602 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603}
604
James Hogan9e443bc2013-11-14 21:15:13 +0000605static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
606 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
608 struct inode *inode;
609 char *name;
610 int err;
611
David Howells0a370e52008-02-07 00:15:50 -0800612 inode = hostfs_iget(ino->i_sb);
613 if (IS_ERR(inode)) {
614 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400619 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700620 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 goto out_put;
622
623 err = read_name(inode, name);
Al Viro5e2df282010-06-06 19:38:18 -0400624
Al Viroe9193052010-06-06 23:16:34 -0400625 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700626 if (err == -ENOENT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 iput(inode);
628 inode = NULL;
629 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700630 else if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 goto out_put;
632
633 d_add(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700634 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 out_put:
637 iput(inode);
638 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700639 return ERR_PTR(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
James Hogan9e443bc2013-11-14 21:15:13 +0000642static int hostfs_link(struct dentry *to, struct inode *ino,
643 struct dentry *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
Jeff Dikef1adc052007-05-08 00:23:18 -0700645 char *from_name, *to_name;
646 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Al Viroc5322222010-06-06 20:42:10 -0400648 if ((from_name = dentry_name(from)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700649 return -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400650 to_name = dentry_name(to);
Jeff Dike84b3db02007-10-16 01:27:13 -0700651 if (to_name == NULL) {
Al Viroe9193052010-06-06 23:16:34 -0400652 __putname(from_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700653 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Jeff Dikef1adc052007-05-08 00:23:18 -0700655 err = link_file(to_name, from_name);
Al Viroe9193052010-06-06 23:16:34 -0400656 __putname(from_name);
657 __putname(to_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700658 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659}
660
James Hogan9e443bc2013-11-14 21:15:13 +0000661static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
663 char *file;
664 int err;
665
Jeff Dike84b3db02007-10-16 01:27:13 -0700666 if (append)
Jeff Dikef1adc052007-05-08 00:23:18 -0700667 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Al Virof8d7e182010-06-06 23:19:04 -0400669 if ((file = dentry_name(dentry)) == NULL)
670 return -ENOMEM;
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 err = unlink_file(file);
Al Viroe9193052010-06-06 23:16:34 -0400673 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700674 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675}
676
James Hogan9e443bc2013-11-14 21:15:13 +0000677static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
678 const char *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
680 char *file;
681 int err;
682
Al Viroc5322222010-06-06 20:42:10 -0400683 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700684 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 err = make_symlink(file, to);
Al Viroe9193052010-06-06 23:16:34 -0400686 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700687 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688}
689
James Hogan9e443bc2013-11-14 21:15:13 +0000690static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
692 char *file;
693 int err;
694
Al Viroc5322222010-06-06 20:42:10 -0400695 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700696 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 err = do_mkdir(file, mode);
Al Viroe9193052010-06-06 23:16:34 -0400698 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700699 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
James Hogan9e443bc2013-11-14 21:15:13 +0000702static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 char *file;
705 int err;
706
Al Viroc5322222010-06-06 20:42:10 -0400707 if ((file = dentry_name(dentry)) == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700708 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 err = do_rmdir(file);
Al Viroe9193052010-06-06 23:16:34 -0400710 __putname(file);
Jeff Dikef1adc052007-05-08 00:23:18 -0700711 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712}
713
Al Viro1a67aaf2011-07-26 01:52:52 -0400714static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
716 struct inode *inode;
717 char *name;
David Howells0a370e52008-02-07 00:15:50 -0800718 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
David Howells0a370e52008-02-07 00:15:50 -0800720 inode = hostfs_iget(dir->i_sb);
721 if (IS_ERR(inode)) {
722 err = PTR_ERR(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 goto out;
David Howells0a370e52008-02-07 00:15:50 -0800724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 err = -ENOMEM;
Al Viroc5322222010-06-06 20:42:10 -0400727 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700728 if (name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 goto out_put;
730
731 init_special_inode(inode, mode, dev);
Johannes Stezenbach88f6cd02007-01-29 13:19:44 -0800732 err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
Vegard Nossum9f2dfda2015-12-16 21:59:56 +0100733 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 goto out_free;
735
736 err = read_name(inode, name);
Al Viroe9193052010-06-06 23:16:34 -0400737 __putname(name);
Al Viro5e2df282010-06-06 19:38:18 -0400738 if (err)
739 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 d_instantiate(dentry, inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700742 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 out_free:
Al Viroe9193052010-06-06 23:16:34 -0400745 __putname(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 out_put:
747 iput(inode);
748 out:
Jeff Dikef1adc052007-05-08 00:23:18 -0700749 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750}
751
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200752static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
753 struct inode *new_dir, struct dentry *new_dentry,
754 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755{
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200756 char *old_name, *new_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 int err;
758
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200759 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
760 return -EINVAL;
761
762 old_name = dentry_name(old_dentry);
763 if (old_name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700764 return -ENOMEM;
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200765 new_name = dentry_name(new_dentry);
766 if (new_name == NULL) {
767 __putname(old_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700768 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 }
Miklos Szeredi9a423bb2014-07-23 15:15:35 +0200770 if (!flags)
771 err = rename_file(old_name, new_name);
772 else
773 err = rename2_file(old_name, new_name, flags);
774
775 __putname(old_name);
776 __putname(new_name);
Jeff Dikef1adc052007-05-08 00:23:18 -0700777 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778}
779
James Hogan9e443bc2013-11-14 21:15:13 +0000780static int hostfs_permission(struct inode *ino, int desired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781{
782 char *name;
783 int r = 0, w = 0, x = 0, err;
784
Al Viro10556cb2011-06-20 19:28:19 -0400785 if (desired & MAY_NOT_BLOCK)
Nick Pigginb74c79e2011-01-07 17:49:58 +1100786 return -ECHILD;
787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 if (desired & MAY_READ) r = 1;
789 if (desired & MAY_WRITE) w = 1;
790 if (desired & MAY_EXEC) x = 1;
Al Viroc5322222010-06-06 20:42:10 -0400791 name = inode_name(ino);
Jeff Dikef1adc052007-05-08 00:23:18 -0700792 if (name == NULL)
793 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
Jeff Dike84b3db02007-10-16 01:27:13 -0700796 S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 err = 0;
798 else
799 err = access_file(name, r, w, x);
Al Viroe9193052010-06-06 23:16:34 -0400800 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700801 if (!err)
Al Viro2830ba72011-06-20 19:16:29 -0400802 err = generic_permission(ino, desired);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return err;
804}
805
James Hogan9e443bc2013-11-14 21:15:13 +0000806static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
David Howells2b0143b2015-03-17 22:25:59 +0000808 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 struct hostfs_iattr attrs;
810 char *name;
811 int err;
812
Christoph Hellwig10257742010-06-04 11:30:02 +0200813 int fd = HOSTFS_I(inode)->fd;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700814
Jan Kara31051c82016-05-26 16:55:18 +0200815 err = setattr_prepare(dentry, attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 if (err)
817 return err;
818
Jeff Dike84b3db02007-10-16 01:27:13 -0700819 if (append)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 attr->ia_valid &= ~ATTR_SIZE;
821
822 attrs.ia_valid = 0;
Jeff Dike84b3db02007-10-16 01:27:13 -0700823 if (attr->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 attrs.ia_valid |= HOSTFS_ATTR_MODE;
825 attrs.ia_mode = attr->ia_mode;
826 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700827 if (attr->ia_valid & ATTR_UID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 attrs.ia_valid |= HOSTFS_ATTR_UID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800829 attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700831 if (attr->ia_valid & ATTR_GID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 attrs.ia_valid |= HOSTFS_ATTR_GID;
Eric W. Biederman29f82ae2012-02-07 16:28:57 -0800833 attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700835 if (attr->ia_valid & ATTR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 attrs.ia_valid |= HOSTFS_ATTR_SIZE;
837 attrs.ia_size = attr->ia_size;
838 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700839 if (attr->ia_valid & ATTR_ATIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 attrs.ia_valid |= HOSTFS_ATTR_ATIME;
841 attrs.ia_atime = attr->ia_atime;
842 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700843 if (attr->ia_valid & ATTR_MTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 attrs.ia_valid |= HOSTFS_ATTR_MTIME;
845 attrs.ia_mtime = attr->ia_mtime;
846 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700847 if (attr->ia_valid & ATTR_CTIME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 attrs.ia_valid |= HOSTFS_ATTR_CTIME;
849 attrs.ia_ctime = attr->ia_ctime;
850 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700851 if (attr->ia_valid & ATTR_ATIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
853 }
Jeff Dike84b3db02007-10-16 01:27:13 -0700854 if (attr->ia_valid & ATTR_MTIME_SET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
856 }
Al Viroc5322222010-06-06 20:42:10 -0400857 name = dentry_name(dentry);
Jeff Dike84b3db02007-10-16 01:27:13 -0700858 if (name == NULL)
Jeff Dikef1adc052007-05-08 00:23:18 -0700859 return -ENOMEM;
Alberto Bertogli5822b7f2007-05-08 00:23:16 -0700860 err = set_attr(name, &attrs, fd);
Al Viroe9193052010-06-06 23:16:34 -0400861 __putname(name);
Jeff Dike84b3db02007-10-16 01:27:13 -0700862 if (err)
Jeff Dikef1adc052007-05-08 00:23:18 -0700863 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
Christoph Hellwig10257742010-06-04 11:30:02 +0200865 if ((attr->ia_valid & ATTR_SIZE) &&
Marco Stornellibc077322012-10-20 12:02:59 +0200866 attr->ia_size != i_size_read(inode))
Marco Stornelli3be2be02012-10-06 10:31:13 +0200867 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200868
869 setattr_copy(inode, attr);
870 mark_inode_dirty(inode);
871 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872}
873
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800874static const struct inode_operations hostfs_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 .permission = hostfs_permission,
876 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877};
878
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800879static const struct inode_operations hostfs_dir_iops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 .create = hostfs_create,
881 .lookup = hostfs_lookup,
882 .link = hostfs_link,
883 .unlink = hostfs_unlink,
884 .symlink = hostfs_symlink,
885 .mkdir = hostfs_mkdir,
886 .rmdir = hostfs_rmdir,
887 .mknod = hostfs_mknod,
Miklos Szeredi2773bf02016-09-27 11:03:58 +0200888 .rename = hostfs_rename2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 .permission = hostfs_permission,
890 .setattr = hostfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891};
892
Al Viro6b255392015-11-17 10:20:54 -0500893static const char *hostfs_get_link(struct dentry *dentry,
Al Virofceef392015-12-29 15:58:39 -0500894 struct inode *inode,
895 struct delayed_call *done)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
Al Viro6b255392015-11-17 10:20:54 -0500897 char *link;
898 if (!dentry)
899 return ERR_PTR(-ECHILD);
Al Virofceef392015-12-29 15:58:39 -0500900 link = kmalloc(PATH_MAX, GFP_KERNEL);
Al Virod0352d32010-06-06 21:51:16 -0400901 if (link) {
902 char *path = dentry_name(dentry);
903 int err = -ENOMEM;
904 if (path) {
Al Viro3b6036d2010-08-18 06:21:10 -0400905 err = hostfs_do_readlink(path, link, PATH_MAX);
Al Virod0352d32010-06-06 21:51:16 -0400906 if (err == PATH_MAX)
907 err = -E2BIG;
Al Viroe9193052010-06-06 23:16:34 -0400908 __putname(path);
Al Virod0352d32010-06-06 21:51:16 -0400909 }
910 if (err < 0) {
Al Virofceef392015-12-29 15:58:39 -0500911 kfree(link);
Al Viro680baac2015-05-02 13:32:22 -0400912 return ERR_PTR(err);
Al Virod0352d32010-06-06 21:51:16 -0400913 }
914 } else {
Al Viro680baac2015-05-02 13:32:22 -0400915 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 }
Al Virod0352d32010-06-06 21:51:16 -0400917
Al Virofceef392015-12-29 15:58:39 -0500918 set_delayed_call(done, kfree_link, link);
919 return link;
Al Virod0352d32010-06-06 21:51:16 -0400920}
921
922static const struct inode_operations hostfs_link_iops = {
Al Viro6b255392015-11-17 10:20:54 -0500923 .get_link = hostfs_get_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924};
925
926static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
927{
928 struct inode *root_inode;
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700929 char *host_root_path, *req_root = d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 int err;
931
932 sb->s_blocksize = 1024;
933 sb->s_blocksize_bits = 10;
934 sb->s_magic = HOSTFS_SUPER_MAGIC;
935 sb->s_op = &hostfs_sbops;
Al Virob26d4cd2013-10-25 18:47:37 -0400936 sb->s_d_op = &simple_dentry_operations;
Wolfgang Illmeyer752fa512009-06-30 11:41:44 -0700937 sb->s_maxbytes = MAX_LFS_FILESIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Paolo 'Blaisorblade' Giarrussoa6eb0be2007-03-07 20:41:08 -0800939 /* NULL is printed as <NULL> by sprintf: avoid that. */
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700940 if (req_root == NULL)
941 req_root = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 err = -ENOMEM;
Al Viro601d2c32010-06-06 17:53:01 -0400944 sb->s_fs_info = host_root_path =
945 kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
Jeff Dike84b3db02007-10-16 01:27:13 -0700946 if (host_root_path == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 goto out;
948
Paolo 'Blaisorblade' Giarrusso75e8def2007-03-29 01:20:33 -0700949 sprintf(host_root_path, "%s/%s", root_ino, req_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Al Viro52b209f2010-06-06 18:43:19 -0400951 root_inode = new_inode(sb);
952 if (!root_inode)
Al Viro601d2c32010-06-06 17:53:01 -0400953 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Al Viro4754b822010-06-06 20:33:12 -0400955 err = read_name(root_inode, host_root_path);
956 if (err)
957 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400958
Al Viro4754b822010-06-06 20:33:12 -0400959 if (S_ISLNK(root_inode->i_mode)) {
Al Viro52b209f2010-06-06 18:43:19 -0400960 char *name = follow_link(host_root_path);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300961 if (IS_ERR(name)) {
Al Viro52b209f2010-06-06 18:43:19 -0400962 err = PTR_ERR(name);
Dan Carpenter8a545f12016-07-13 13:12:34 +0300963 goto out_put;
964 }
965 err = read_name(root_inode, name);
Al Viro52b209f2010-06-06 18:43:19 -0400966 kfree(name);
Al Viro4754b822010-06-06 20:33:12 -0400967 if (err)
968 goto out_put;
Al Viro52b209f2010-06-06 18:43:19 -0400969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 err = -ENOMEM;
Al Viro48fde702012-01-08 22:15:13 -0500972 sb->s_root = d_make_root(root_inode);
Jeff Dike84b3db02007-10-16 01:27:13 -0700973 if (sb->s_root == NULL)
Al Viro48fde702012-01-08 22:15:13 -0500974 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
Jeff Dikef1adc052007-05-08 00:23:18 -0700976 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Jeff Dikef1adc052007-05-08 00:23:18 -0700978out_put:
979 iput(root_inode);
Jeff Dikef1adc052007-05-08 00:23:18 -0700980out:
981 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982}
983
Al Viro3c26ff62010-07-25 11:46:36 +0400984static struct dentry *hostfs_read_sb(struct file_system_type *type,
David Howells454e2392006-06-23 02:02:57 -0700985 int flags, const char *dev_name,
Al Viro3c26ff62010-07-25 11:46:36 +0400986 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
Al Viro3c26ff62010-07-25 11:46:36 +0400988 return mount_nodev(type, flags, data, hostfs_fill_sb_common);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989}
990
Al Viro601d2c32010-06-06 17:53:01 -0400991static void hostfs_kill_sb(struct super_block *s)
992{
993 kill_anon_super(s);
994 kfree(s->s_fs_info);
995}
996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997static struct file_system_type hostfs_type = {
998 .owner = THIS_MODULE,
999 .name = "hostfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001000 .mount = hostfs_read_sb,
Al Viro601d2c32010-06-06 17:53:01 -04001001 .kill_sb = hostfs_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 .fs_flags = 0,
1003};
Eric W. Biederman3e64fe52013-03-11 07:05:42 -07001004MODULE_ALIAS_FS("hostfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
1006static int __init init_hostfs(void)
1007{
Jeff Dikef1adc052007-05-08 00:23:18 -07001008 return register_filesystem(&hostfs_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009}
1010
1011static void __exit exit_hostfs(void)
1012{
1013 unregister_filesystem(&hostfs_type);
1014}
1015
1016module_init(init_hostfs)
1017module_exit(exit_hostfs)
1018MODULE_LICENSE("GPL");