Blame view

fs/hostfs/hostfs_kern.c 20.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
f1adc05e7   Jeff Dike   uml: hostfs style...
2
   * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
   * Licensed under the GPL
   *
   * Ported the filesystem routines to 2.5.
   * 2003-02-10 Petr Baudis <pasky@ucw.cz>
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <linux/fs.h>
2b3b9bb03   James Hogan   hostfs: move HOST...
9
  #include <linux/magic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
  #include <linux/module.h>
84b3db04c   Jeff Dike   uml: fix hostfs s...
11
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/statfs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
14
  #include <linux/slab.h>
dd2cc4dff   Miklos Szeredi   mount options: fi...
15
  #include <linux/seq_file.h>
6966a9775   Jiri Kosina   UML: fix hostfs b...
16
  #include <linux/mount.h>
d0352d3ed   Al Viro   hostfs: sanitize ...
17
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include "hostfs.h"
37185b332   Al Viro   um: get rid of po...
19
20
  #include <init.h>
  #include <kern.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  
  struct hostfs_inode_info {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  	int fd;
aeb5d7270   Al Viro   [PATCH] introduce...
24
  	fmode_t mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  	struct inode vfs_inode;
69886e676   Richard Weinberger   hostfs: hostfs_fi...
26
  	struct mutex open_mutex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
  };
  
  static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
31
  	return list_entry(inode, struct hostfs_inode_info, vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  }
496ad9aa8   Al Viro   new helper: file_...
33
  #define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  /* Changed in hostfs_args before the kernel starts running */
a6eb0be6d   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
36
  static char *root_ino = "";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  static int append = 0;
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
38
39
  static const struct inode_operations hostfs_iops;
  static const struct inode_operations hostfs_dir_iops;
d0352d3ed   Al Viro   hostfs: sanitize ...
40
  static const struct inode_operations hostfs_link_iops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
46
47
  
  #ifndef MODULE
  static int __init hostfs_args(char *options, int *add)
  {
  	char *ptr;
  
  	ptr = strchr(options, ',');
84b3db04c   Jeff Dike   uml: fix hostfs s...
48
  	if (ptr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  		*ptr++ = '\0';
84b3db04c   Jeff Dike   uml: fix hostfs s...
50
  	if (*options != '\0')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
  		root_ino = options;
  
  	options = ptr;
84b3db04c   Jeff Dike   uml: fix hostfs s...
54
  	while (options) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  		ptr = strchr(options, ',');
84b3db04c   Jeff Dike   uml: fix hostfs s...
56
  		if (ptr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  			*ptr++ = '\0';
84b3db04c   Jeff Dike   uml: fix hostfs s...
58
59
  		if (*options != '\0') {
  			if (!strcmp(options, "append"))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
  				append = 1;
  			else printf("hostfs_args - unsupported option - %s
  ",
  				    options);
  		}
  		options = ptr;
  	}
f1adc05e7   Jeff Dike   uml: hostfs style...
67
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  }
  
  __uml_setup("hostfs=", hostfs_args,
  "hostfs=<root dir>,<flags>,...
  "
  "    This is used to set hostfs parameters.  The root directory argument
  "
  "    is used to confine all hostfs mounts to within the specified directory
  "
  "    tree on the host.  If this isn't specified, then a user inside UML can
  "
  "    mount anything on the host that's accessible to the user that's running
  "
  "    it.
  "
  "    The only flag currently supported is 'append', which specifies that all
  "
  "    files opened by hostfs will be opened in append mode.
  
  "
  );
  #endif
e9193059b   Al Viro   hostfs: fix races...
90
  static char *__dentry_name(struct dentry *dentry, char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  {
ec2447c27   Nick Piggin   hostfs: simplify ...
92
  	char *p = dentry_path_raw(dentry, name, PATH_MAX);
e9193059b   Al Viro   hostfs: fix races...
93
94
  	char *root;
  	size_t len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95

e9193059b   Al Viro   hostfs: fix races...
96
97
98
99
  	root = dentry->d_sb->s_fs_info;
  	len = strlen(root);
  	if (IS_ERR(p)) {
  		__putname(name);
f1adc05e7   Jeff Dike   uml: hostfs style...
100
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  	}
aad50b1e0   Richard Weinberger   hostfs: Add a BUG...
102
103
104
105
106
107
  
  	/*
  	 * This function relies on the fact that dentry_path_raw() will place
  	 * the path name at the end of the provided buffer.
  	 */
  	BUG_ON(p + strlen(p) + 1 != name + PATH_MAX);
850a496f9   Al Viro   hostfs: dumb (and...
108
  	strlcpy(name, root, PATH_MAX);
e9193059b   Al Viro   hostfs: fix races...
109
110
111
112
  	if (len > p - name) {
  		__putname(name);
  		return NULL;
  	}
c278e81b8   Richard Weinberger   hostfs: Remove op...
113
114
115
  
  	if (p > name + len)
  		strcpy(name + len, p);
f1adc05e7   Jeff Dike   uml: hostfs style...
116
  	return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  }
e9193059b   Al Viro   hostfs: fix races...
118
119
120
121
122
  static char *dentry_name(struct dentry *dentry)
  {
  	char *name = __getname();
  	if (!name)
  		return NULL;
9dcc5e8a4   James Hogan   hostfs: remove "w...
123
  	return __dentry_name(dentry, name);
e9193059b   Al Viro   hostfs: fix races...
124
  }
c5322220e   Al Viro   hostfs: get rid o...
125
  static char *inode_name(struct inode *ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
  {
  	struct dentry *dentry;
ec2447c27   Nick Piggin   hostfs: simplify ...
128
  	char *name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

ec2447c27   Nick Piggin   hostfs: simplify ...
130
131
  	dentry = d_find_alias(ino);
  	if (!dentry)
e9193059b   Al Viro   hostfs: fix races...
132
  		return NULL;
ec2447c27   Nick Piggin   hostfs: simplify ...
133
134
135
136
137
138
  
  	name = dentry_name(dentry);
  
  	dput(dentry);
  
  	return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
  static char *follow_link(char *link)
  {
  	int len, n;
  	char *name, *resolved, *end;
7c9509924   Richard Weinberger   hostfs: Use __get...
144
145
  	name = __getname();
  	if (!name) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  		n = -ENOMEM;
7c9509924   Richard Weinberger   hostfs: Use __get...
147
  		goto out_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  	}
7c9509924   Richard Weinberger   hostfs: Use __get...
149
150
  
  	n = hostfs_do_readlink(link, name, PATH_MAX);
84b3db04c   Jeff Dike   uml: fix hostfs s...
151
  	if (n < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  		goto out_free;
7c9509924   Richard Weinberger   hostfs: Use __get...
153
154
155
156
  	else if (n == PATH_MAX) {
  		n = -E2BIG;
  		goto out_free;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157

84b3db04c   Jeff Dike   uml: fix hostfs s...
158
  	if (*name == '/')
f1adc05e7   Jeff Dike   uml: hostfs style...
159
  		return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
  
  	end = strrchr(link, '/');
84b3db04c   Jeff Dike   uml: fix hostfs s...
162
  	if (end == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
163
  		return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
168
  
  	*(end + 1) = '\0';
  	len = strlen(link) + strlen(name) + 1;
  
  	resolved = kmalloc(len, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
169
  	if (resolved == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
174
  		n = -ENOMEM;
  		goto out_free;
  	}
  
  	sprintf(resolved, "%s%s", link, name);
7c9509924   Richard Weinberger   hostfs: Use __get...
175
  	__putname(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  	kfree(link);
f1adc05e7   Jeff Dike   uml: hostfs style...
177
  	return resolved;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
  
   out_free:
7c9509924   Richard Weinberger   hostfs: Use __get...
180
  	__putname(name);
f1adc05e7   Jeff Dike   uml: hostfs style...
181
  	return ERR_PTR(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  }
0a370e5de   David Howells   iget: stop HOSTFS...
183
184
  static struct inode *hostfs_iget(struct super_block *sb)
  {
52b209f7b   Al Viro   get rid of hostfs...
185
  	struct inode *inode = new_inode(sb);
0a370e5de   David Howells   iget: stop HOSTFS...
186
187
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
0a370e5de   David Howells   iget: stop HOSTFS...
188
189
  	return inode;
  }
9e443bc36   James Hogan   um: hostfs: make ...
190
  static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  {
84b3db04c   Jeff Dike   uml: fix hostfs s...
192
193
  	/*
  	 * do_statfs uses struct statfs64 internally, but the linux kernel
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
201
202
  	 * struct statfs still has 32-bit versions for most of these fields,
  	 * so we convert them here
  	 */
  	int err;
  	long long f_blocks;
  	long long f_bfree;
  	long long f_bavail;
  	long long f_files;
  	long long f_ffree;
601d2c38b   Al Viro   hostfs: don't kee...
203
  	err = do_statfs(dentry->d_sb->s_fs_info,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
  			&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
  			&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
1b627d577   Richard Weinberger   hostfs: fix UML c...
206
  			&sf->f_namelen);
84b3db04c   Jeff Dike   uml: fix hostfs s...
207
  	if (err)
f1adc05e7   Jeff Dike   uml: hostfs style...
208
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
  	sf->f_blocks = f_blocks;
  	sf->f_bfree = f_bfree;
  	sf->f_bavail = f_bavail;
  	sf->f_files = f_files;
  	sf->f_ffree = f_ffree;
  	sf->f_type = HOSTFS_SUPER_MAGIC;
f1adc05e7   Jeff Dike   uml: hostfs style...
215
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
  }
  
  static struct inode *hostfs_alloc_inode(struct super_block *sb)
  {
  	struct hostfs_inode_info *hi;
371fdab10   James Hogan   hostfs: use kmall...
221
  	hi = kmalloc(sizeof(*hi), GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
222
  	if (hi == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
223
  		return NULL;
601d2c38b   Al Viro   hostfs: don't kee...
224
  	hi->fd = -1;
371fdab10   James Hogan   hostfs: use kmall...
225
  	hi->mode = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  	inode_init_once(&hi->vfs_inode);
69886e676   Richard Weinberger   hostfs: hostfs_fi...
227
  	mutex_init(&hi->open_mutex);
f1adc05e7   Jeff Dike   uml: hostfs style...
228
  	return &hi->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  }
e971a6d7b   Al Viro   stop icache pollu...
230
  static void hostfs_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  {
91b0abe36   Johannes Weiner   mm + fs: store sh...
232
  	truncate_inode_pages_final(&inode->i_data);
dbd5768f8   Jan Kara   vfs: Rename end_w...
233
  	clear_inode(inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
234
  	if (HOSTFS_I(inode)->fd != -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
  		close_file(&HOSTFS_I(inode)->fd);
  		HOSTFS_I(inode)->fd = -1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
239
  static void hostfs_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
241
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
  	kfree(HOSTFS_I(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
244
245
246
247
248
  
  static void hostfs_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, hostfs_i_callback);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249

34c80b1d9   Al Viro   vfs: switch ->sho...
250
  static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
dd2cc4dff   Miklos Szeredi   mount options: fi...
251
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
252
  	const char *root_path = root->d_sb->s_fs_info;
dd2cc4dff   Miklos Szeredi   mount options: fi...
253
254
255
256
  	size_t offset = strlen(root_ino) + 1;
  
  	if (strlen(root_path) > offset)
  		seq_printf(seq, ",%s", root_path + offset);
7f74a6687   Richard Weinberger   hostfs: Report ap...
257
258
  	if (append)
  		seq_puts(seq, ",append");
dd2cc4dff   Miklos Szeredi   mount options: fi...
259
260
  	return 0;
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
261
  static const struct super_operations hostfs_sbops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  	.alloc_inode	= hostfs_alloc_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  	.destroy_inode	= hostfs_destroy_inode,
e971a6d7b   Al Viro   stop icache pollu...
264
  	.evict_inode	= hostfs_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  	.statfs		= hostfs_statfs,
dd2cc4dff   Miklos Szeredi   mount options: fi...
266
  	.show_options	= hostfs_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  };
9e443bc36   James Hogan   um: hostfs: make ...
268
  static int hostfs_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
272
273
  {
  	void *dir;
  	char *name;
  	unsigned long long next, ino;
  	int error, len;
3ee6bd8e8   Geert Uytterhoeven   uml/hostfs: Propa...
274
  	unsigned int type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275

c5322220e   Al Viro   hostfs: get rid o...
276
  	name = dentry_name(file->f_path.dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
277
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
278
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  	dir = open_dir(name, &error);
e9193059b   Al Viro   hostfs: fix races...
280
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
281
  	if (dir == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
282
  		return -error;
8e28bc7e7   Al Viro   [readdir] convert...
283
  	next = ctx->pos;
0c9bd6365   Richard Weinberger   um: hostfs: Reduc...
284
  	seek_dir(dir, next);
3ee6bd8e8   Geert Uytterhoeven   uml/hostfs: Propa...
285
  	while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
8e28bc7e7   Al Viro   [readdir] convert...
286
287
288
  		if (!dir_emit(ctx, name, len, ino, type))
  			break;
  		ctx->pos = next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
  	}
  	close_dir(dir);
f1adc05e7   Jeff Dike   uml: hostfs style...
291
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  }
4c6dcafc6   Richard Weinberger   hostfs: Allow fsy...
293
  static int hostfs_open(struct inode *ino, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
  {
  	char *name;
bd1052a24   Richard Weinberger   hostfs: Remove su...
296
  	fmode_t mode;
f8ad850f1   Al Viro   try to get rid of...
297
  	int err;
bd1052a24   Richard Weinberger   hostfs: Remove su...
298
  	int r, w, fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
  
  	mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
84b3db04c   Jeff Dike   uml: fix hostfs s...
301
  	if ((mode & HOSTFS_I(ino)->mode) == mode)
f1adc05e7   Jeff Dike   uml: hostfs style...
302
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303

f8ad850f1   Al Viro   try to get rid of...
304
  	mode |= HOSTFS_I(ino)->mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305

f8ad850f1   Al Viro   try to get rid of...
306
  retry:
a9d1958b4   Richard Weinberger   hostfs: hostfs_op...
307
  	r = w = 0;
f8ad850f1   Al Viro   try to get rid of...
308
  	if (mode & FMODE_READ)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  		r = 1;
f8ad850f1   Al Viro   try to get rid of...
310
  	if (mode & FMODE_WRITE)
112a5da71   Richard Weinberger   hostfs: Remove su...
311
  		r = w = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312

c5322220e   Al Viro   hostfs: get rid o...
313
  	name = dentry_name(file->f_path.dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
314
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
315
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
  
  	fd = open_file(name, r, w, append);
e9193059b   Al Viro   hostfs: fix races...
318
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
319
  	if (fd < 0)
f1adc05e7   Jeff Dike   uml: hostfs style...
320
  		return fd;
f8ad850f1   Al Viro   try to get rid of...
321

69886e676   Richard Weinberger   hostfs: hostfs_fi...
322
  	mutex_lock(&HOSTFS_I(ino)->open_mutex);
f8ad850f1   Al Viro   try to get rid of...
323
324
  	/* somebody else had handled it first? */
  	if ((mode & HOSTFS_I(ino)->mode) == mode) {
69886e676   Richard Weinberger   hostfs: hostfs_fi...
325
  		mutex_unlock(&HOSTFS_I(ino)->open_mutex);
af9556586   Richard Weinberger   hostfs: hostfs_fi...
326
  		close_file(&fd);
f8ad850f1   Al Viro   try to get rid of...
327
328
329
330
  		return 0;
  	}
  	if ((mode | HOSTFS_I(ino)->mode) != mode) {
  		mode |= HOSTFS_I(ino)->mode;
69886e676   Richard Weinberger   hostfs: hostfs_fi...
331
  		mutex_unlock(&HOSTFS_I(ino)->open_mutex);
f8ad850f1   Al Viro   try to get rid of...
332
333
334
335
336
337
338
339
340
  		close_file(&fd);
  		goto retry;
  	}
  	if (HOSTFS_I(ino)->fd == -1) {
  		HOSTFS_I(ino)->fd = fd;
  	} else {
  		err = replace_file(fd, HOSTFS_I(ino)->fd);
  		close_file(&fd);
  		if (err < 0) {
69886e676   Richard Weinberger   hostfs: hostfs_fi...
341
  			mutex_unlock(&HOSTFS_I(ino)->open_mutex);
f8ad850f1   Al Viro   try to get rid of...
342
343
344
345
  			return err;
  		}
  	}
  	HOSTFS_I(ino)->mode = mode;
69886e676   Richard Weinberger   hostfs: hostfs_fi...
346
  	mutex_unlock(&HOSTFS_I(ino)->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347

f1adc05e7   Jeff Dike   uml: hostfs style...
348
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  }
65984ff9d   Richard Weinberger   um: hostfs: Fix w...
350
351
352
353
354
355
  static int hostfs_file_release(struct inode *inode, struct file *file)
  {
  	filemap_write_and_wait(inode->i_mapping);
  
  	return 0;
  }
9e443bc36   James Hogan   um: hostfs: make ...
356
357
  static int hostfs_fsync(struct file *file, loff_t start, loff_t end,
  			int datasync)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  {
02c24a821   Josef Bacik   fs: push i_mutex ...
359
360
361
362
363
364
365
366
367
368
369
370
  	struct inode *inode = file->f_mapping->host;
  	int ret;
  
  	ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
  	if (ret)
  		return ret;
  
  	mutex_lock(&inode->i_mutex);
  	ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
  	mutex_unlock(&inode->i_mutex);
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
372
  static const struct file_operations hostfs_file_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  	.llseek		= generic_file_llseek,
5ffc4ef45   Jens Axboe   sendfile: remove ...
374
  	.splice_read	= generic_file_splice_read,
aad4f8bb4   Al Viro   switch simple gen...
375
  	.read_iter	= generic_file_read_iter,
8174202b3   Al Viro   write_iter varian...
376
  	.write_iter	= generic_file_write_iter,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
  	.mmap		= generic_file_mmap,
4c6dcafc6   Richard Weinberger   hostfs: Allow fsy...
378
  	.open		= hostfs_open,
65984ff9d   Richard Weinberger   um: hostfs: Fix w...
379
  	.release	= hostfs_file_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
  	.fsync		= hostfs_fsync,
  };
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
382
  static const struct file_operations hostfs_dir_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  	.llseek		= generic_file_llseek,
8e28bc7e7   Al Viro   [readdir] convert...
384
  	.iterate	= hostfs_readdir,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  	.read		= generic_read_dir,
4c6dcafc6   Richard Weinberger   hostfs: Allow fsy...
386
387
  	.open		= hostfs_open,
  	.fsync		= hostfs_fsync,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  };
9e443bc36   James Hogan   um: hostfs: make ...
389
  static int hostfs_writepage(struct page *page, struct writeback_control *wbc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
393
  {
  	struct address_space *mapping = page->mapping;
  	struct inode *inode = mapping->host;
  	char *buffer;
af6aa1b9c   Richard Weinberger   hostfs: Use page_...
394
  	loff_t base = page_offset(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
399
400
401
402
  	int count = PAGE_CACHE_SIZE;
  	int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
  	int err;
  
  	if (page->index >= end_index)
  		count = inode->i_size & (PAGE_CACHE_SIZE-1);
  
  	buffer = kmap(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
  
  	err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
84b3db04c   Jeff Dike   uml: fix hostfs s...
405
  	if (err != count) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  		ClearPageUptodate(page);
  		goto out;
  	}
  
  	if (base > inode->i_size)
  		inode->i_size = base;
  
  	if (PageError(page))
  		ClearPageError(page);
  	err = 0;
  
   out:
  	kunmap(page);
  
  	unlock_page(page);
  	return err;
  }
9e443bc36   James Hogan   um: hostfs: make ...
423
  static int hostfs_readpage(struct file *file, struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
  {
  	char *buffer;
af6aa1b9c   Richard Weinberger   hostfs: Use page_...
426
  	loff_t start = page_offset(page);
b86b413a3   Richard Weinberger   hostfs: Set page ...
427
  	int bytes_read, ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  	buffer = kmap(page);
41761ddfa   Richard Weinberger   hostfs: Make host...
430
  	bytes_read = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
  			PAGE_CACHE_SIZE);
41761ddfa   Richard Weinberger   hostfs: Make host...
432
  	if (bytes_read < 0) {
b86b413a3   Richard Weinberger   hostfs: Set page ...
433
434
  		ClearPageUptodate(page);
  		SetPageError(page);
41761ddfa   Richard Weinberger   hostfs: Make host...
435
  		ret = bytes_read;
84b3db04c   Jeff Dike   uml: fix hostfs s...
436
  		goto out;
41761ddfa   Richard Weinberger   hostfs: Make host...
437
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438

41761ddfa   Richard Weinberger   hostfs: Make host...
439
  	memset(buffer + bytes_read, 0, PAGE_CACHE_SIZE - bytes_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440

b86b413a3   Richard Weinberger   hostfs: Set page ...
441
  	ClearPageError(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  	SetPageUptodate(page);
b86b413a3   Richard Weinberger   hostfs: Set page ...
443

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
   out:
b86b413a3   Richard Weinberger   hostfs: Set page ...
445
  	flush_dcache_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
  	kunmap(page);
  	unlock_page(page);
41761ddfa   Richard Weinberger   hostfs: Make host...
448
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  }
9e443bc36   James Hogan   um: hostfs: make ...
450
451
452
  static int hostfs_write_begin(struct file *file, struct address_space *mapping,
  			      loff_t pos, unsigned len, unsigned flags,
  			      struct page **pagep, void **fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  {
ae361ff46   Nick Piggin   hostfs: convert t...
454
  	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455

54566b2c1   Nick Piggin   fs: symlink write...
456
  	*pagep = grab_cache_page_write_begin(mapping, index, flags);
ae361ff46   Nick Piggin   hostfs: convert t...
457
458
459
  	if (!*pagep)
  		return -ENOMEM;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  }
9e443bc36   James Hogan   um: hostfs: make ...
461
462
463
  static int hostfs_write_end(struct file *file, struct address_space *mapping,
  			    loff_t pos, unsigned len, unsigned copied,
  			    struct page *page, void *fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  	struct inode *inode = mapping->host;
ae361ff46   Nick Piggin   hostfs: convert t...
466
467
468
  	void *buffer;
  	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	buffer = kmap(page);
ae361ff46   Nick Piggin   hostfs: convert t...
471
472
  	err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
  	kunmap(page);
30f04a4ef   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
473

ae361ff46   Nick Piggin   hostfs: convert t...
474
475
  	if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
  		SetPageUptodate(page);
30f04a4ef   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
476

84b3db04c   Jeff Dike   uml: fix hostfs s...
477
478
  	/*
  	 * If err > 0, write_file has added err to pos, so we are comparing
ae361ff46   Nick Piggin   hostfs: convert t...
479
480
481
482
483
484
  	 * i_size against the last byte written.
  	 */
  	if (err > 0 && (pos > inode->i_size))
  		inode->i_size = pos;
  	unlock_page(page);
  	page_cache_release(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485

f1adc05e7   Jeff Dike   uml: hostfs style...
486
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
488
  static const struct address_space_operations hostfs_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
  	.writepage 	= hostfs_writepage,
  	.readpage	= hostfs_readpage,
ffa0aea68   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml - hos...
491
  	.set_page_dirty = __set_page_dirty_nobuffers,
ae361ff46   Nick Piggin   hostfs: convert t...
492
493
  	.write_begin	= hostfs_write_begin,
  	.write_end	= hostfs_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
  };
4754b8255   Al Viro   hostfs: get rid o...
495
  static int read_name(struct inode *ino, char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  {
4754b8255   Al Viro   hostfs: get rid o...
497
498
499
500
501
  	dev_t rdev;
  	struct hostfs_stat st;
  	int err = stat_file(name, &st, -1);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502

5e2df28cc   Al Viro   hostfs: pass path...
503
  	/* Reencode maj and min with the kernel encoding.*/
4754b8255   Al Viro   hostfs: get rid o...
504
  	rdev = MKDEV(st.maj, st.min);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505

4754b8255   Al Viro   hostfs: get rid o...
506
507
  	switch (st.mode & S_IFMT) {
  	case S_IFLNK:
d0352d3ed   Al Viro   hostfs: sanitize ...
508
  		ino->i_op = &hostfs_link_iops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  		break;
4754b8255   Al Viro   hostfs: get rid o...
510
511
512
  	case S_IFDIR:
  		ino->i_op = &hostfs_dir_iops;
  		ino->i_fop = &hostfs_dir_fops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  		break;
4754b8255   Al Viro   hostfs: get rid o...
514
515
516
517
518
519
  	case S_IFCHR:
  	case S_IFBLK:
  	case S_IFIFO:
  	case S_IFSOCK:
  		init_special_inode(ino, st.mode & S_IFMT, rdev);
  		ino->i_op = &hostfs_iops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  		break;
2ad2dca6f   Richard Weinberger   hostfs: Handle bo...
521
  	case S_IFREG:
4754b8255   Al Viro   hostfs: get rid o...
522
523
524
  		ino->i_op = &hostfs_iops;
  		ino->i_fop = &hostfs_file_fops;
  		ino->i_mapping->a_ops = &hostfs_aops;
2ad2dca6f   Richard Weinberger   hostfs: Handle bo...
525
526
527
  		break;
  	default:
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  	}
4754b8255   Al Viro   hostfs: get rid o...
529
530
531
  
  	ino->i_ino = st.ino;
  	ino->i_mode = st.mode;
bfe868486   Miklos Szeredi   filesystems: add ...
532
  	set_nlink(ino, st.nlink);
29f82ae56   Eric W. Biederman   userns: Convert h...
533
534
  	i_uid_write(ino, st.uid);
  	i_gid_write(ino, st.gid);
4754b8255   Al Viro   hostfs: get rid o...
535
536
537
538
539
540
  	ino->i_atime = st.atime;
  	ino->i_mtime = st.mtime;
  	ino->i_ctime = st.ctime;
  	ino->i_size = st.size;
  	ino->i_blocks = st.blocks;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  }
9e443bc36   James Hogan   um: hostfs: make ...
542
543
  static int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
  			 bool excl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
  {
  	struct inode *inode;
  	char *name;
  	int error, fd;
0a370e5de   David Howells   iget: stop HOSTFS...
548
549
550
  	inode = hostfs_iget(dir->i_sb);
  	if (IS_ERR(inode)) {
  		error = PTR_ERR(inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
551
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
552
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  	error = -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
555
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
556
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  		goto out_put;
b98b91029   Richard Weinberger   hostfs: No need t...
558
  	fd = file_create(name, mode & S_IFMT);
4754b8255   Al Viro   hostfs: get rid o...
559
  	if (fd < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
  		error = fd;
4754b8255   Al Viro   hostfs: get rid o...
561
  	else
5e2df28cc   Al Viro   hostfs: pass path...
562
  		error = read_name(inode, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563

e9193059b   Al Viro   hostfs: fix races...
564
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
565
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
570
  		goto out_put;
  
  	HOSTFS_I(inode)->fd = fd;
  	HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
  	d_instantiate(dentry, inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
571
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
574
575
  
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
576
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  }
9e443bc36   James Hogan   um: hostfs: make ...
578
579
  static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
  				    unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
  {
  	struct inode *inode;
  	char *name;
  	int err;
0a370e5de   David Howells   iget: stop HOSTFS...
584
585
586
  	inode = hostfs_iget(ino->i_sb);
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
588
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
  	err = -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
591
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
592
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
  		goto out_put;
  
  	err = read_name(inode, name);
5e2df28cc   Al Viro   hostfs: pass path...
596

e9193059b   Al Viro   hostfs: fix races...
597
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
598
  	if (err == -ENOENT) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
  		iput(inode);
  		inode = NULL;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
602
  	else if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
  		goto out_put;
  
  	d_add(dentry, inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
606
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
609
610
  
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
611
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  }
9e443bc36   James Hogan   um: hostfs: make ...
613
614
  static int hostfs_link(struct dentry *to, struct inode *ino,
  		       struct dentry *from)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
616
617
  	char *from_name, *to_name;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618

c5322220e   Al Viro   hostfs: get rid o...
619
  	if ((from_name = dentry_name(from)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
620
  		return -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
621
  	to_name = dentry_name(to);
84b3db04c   Jeff Dike   uml: fix hostfs s...
622
  	if (to_name == NULL) {
e9193059b   Al Viro   hostfs: fix races...
623
  		__putname(from_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
624
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  	}
f1adc05e7   Jeff Dike   uml: hostfs style...
626
  	err = link_file(to_name, from_name);
e9193059b   Al Viro   hostfs: fix races...
627
628
  	__putname(from_name);
  	__putname(to_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
629
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  }
9e443bc36   James Hogan   um: hostfs: make ...
631
  static int hostfs_unlink(struct inode *ino, struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
  {
  	char *file;
  	int err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
635
  	if (append)
f1adc05e7   Jeff Dike   uml: hostfs style...
636
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637

f8d7e1877   Al Viro   leak in hostfs_un...
638
639
  	if ((file = dentry_name(dentry)) == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  	err = unlink_file(file);
e9193059b   Al Viro   hostfs: fix races...
641
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
642
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
  }
9e443bc36   James Hogan   um: hostfs: make ...
644
645
  static int hostfs_symlink(struct inode *ino, struct dentry *dentry,
  			  const char *to)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
  {
  	char *file;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
649
  	if ((file = dentry_name(dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
650
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  	err = make_symlink(file, to);
e9193059b   Al Viro   hostfs: fix races...
652
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
653
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  }
9e443bc36   James Hogan   um: hostfs: make ...
655
  static int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
  {
  	char *file;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
659
  	if ((file = dentry_name(dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
660
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  	err = do_mkdir(file, mode);
e9193059b   Al Viro   hostfs: fix races...
662
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
663
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  }
9e443bc36   James Hogan   um: hostfs: make ...
665
  static int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
667
668
  {
  	char *file;
  	int err;
c5322220e   Al Viro   hostfs: get rid o...
669
  	if ((file = dentry_name(dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
670
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  	err = do_rmdir(file);
e9193059b   Al Viro   hostfs: fix races...
672
  	__putname(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
673
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
  }
1a67aafb5   Al Viro   switch ->mknod() ...
675
  static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
678
  {
  	struct inode *inode;
  	char *name;
0a370e5de   David Howells   iget: stop HOSTFS...
679
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680

0a370e5de   David Howells   iget: stop HOSTFS...
681
682
683
  	inode = hostfs_iget(dir->i_sb);
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
685
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
  	err = -ENOMEM;
c5322220e   Al Viro   hostfs: get rid o...
688
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
689
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
692
  		goto out_put;
  
  	init_special_inode(inode, mode, dev);
88f6cd0c3   Johannes Stezenbach   [PATCH] uml: fix ...
693
  	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
e9193059b   Al Viro   hostfs: fix races...
694
  	if (!err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
697
  		goto out_free;
  
  	err = read_name(inode, name);
e9193059b   Al Viro   hostfs: fix races...
698
  	__putname(name);
5e2df28cc   Al Viro   hostfs: pass path...
699
700
  	if (err)
  		goto out_put;
84b3db04c   Jeff Dike   uml: fix hostfs s...
701
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
  		goto out_put;
  
  	d_instantiate(dentry, inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
705
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
  
   out_free:
e9193059b   Al Viro   hostfs: fix races...
708
  	__putname(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
712
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
  }
9a423bb6e   Miklos Szeredi   hostfs: support r...
714
715
716
  static int hostfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
  			  struct inode *new_dir, struct dentry *new_dentry,
  			  unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
  {
9a423bb6e   Miklos Szeredi   hostfs: support r...
718
  	char *old_name, *new_name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
  	int err;
9a423bb6e   Miklos Szeredi   hostfs: support r...
720
721
722
723
724
  	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
  		return -EINVAL;
  
  	old_name = dentry_name(old_dentry);
  	if (old_name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
725
  		return -ENOMEM;
9a423bb6e   Miklos Szeredi   hostfs: support r...
726
727
728
  	new_name = dentry_name(new_dentry);
  	if (new_name == NULL) {
  		__putname(old_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
729
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  	}
9a423bb6e   Miklos Szeredi   hostfs: support r...
731
732
733
734
735
736
737
  	if (!flags)
  		err = rename_file(old_name, new_name);
  	else
  		err = rename2_file(old_name, new_name, flags);
  
  	__putname(old_name);
  	__putname(new_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
738
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
  }
9e443bc36   James Hogan   um: hostfs: make ...
740
  static int hostfs_permission(struct inode *ino, int desired)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
  {
  	char *name;
  	int r = 0, w = 0, x = 0, err;
10556cb21   Al Viro   ->permission() sa...
744
  	if (desired & MAY_NOT_BLOCK)
b74c79e99   Nick Piggin   fs: provide rcu-w...
745
  		return -ECHILD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
  	if (desired & MAY_READ) r = 1;
  	if (desired & MAY_WRITE) w = 1;
  	if (desired & MAY_EXEC) x = 1;
c5322220e   Al Viro   hostfs: get rid o...
749
  	name = inode_name(ino);
f1adc05e7   Jeff Dike   uml: hostfs style...
750
751
  	if (name == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
  
  	if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
84b3db04c   Jeff Dike   uml: fix hostfs s...
754
  	    S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
757
  		err = 0;
  	else
  		err = access_file(name, r, w, x);
e9193059b   Al Viro   hostfs: fix races...
758
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
759
  	if (!err)
2830ba7f3   Al Viro   ->permission() sa...
760
  		err = generic_permission(ino, desired);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
762
  	return err;
  }
9e443bc36   James Hogan   um: hostfs: make ...
763
  static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
  {
2b0143b5c   David Howells   VFS: normal files...
765
  	struct inode *inode = d_inode(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
  	struct hostfs_iattr attrs;
  	char *name;
  	int err;
1025774ce   Christoph Hellwig   remove inode_setattr
769
  	int fd = HOSTFS_I(inode)->fd;
5822b7fac   Alberto Bertogli   uml: make hostfs_...
770

1025774ce   Christoph Hellwig   remove inode_setattr
771
  	err = inode_change_ok(inode, attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
  	if (err)
  		return err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
774
  	if (append)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
  		attr->ia_valid &= ~ATTR_SIZE;
  
  	attrs.ia_valid = 0;
84b3db04c   Jeff Dike   uml: fix hostfs s...
778
  	if (attr->ia_valid & ATTR_MODE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
  		attrs.ia_valid |= HOSTFS_ATTR_MODE;
  		attrs.ia_mode = attr->ia_mode;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
782
  	if (attr->ia_valid & ATTR_UID) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  		attrs.ia_valid |= HOSTFS_ATTR_UID;
29f82ae56   Eric W. Biederman   userns: Convert h...
784
  		attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
786
  	if (attr->ia_valid & ATTR_GID) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  		attrs.ia_valid |= HOSTFS_ATTR_GID;
29f82ae56   Eric W. Biederman   userns: Convert h...
788
  		attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
790
  	if (attr->ia_valid & ATTR_SIZE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
793
  		attrs.ia_valid |= HOSTFS_ATTR_SIZE;
  		attrs.ia_size = attr->ia_size;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
794
  	if (attr->ia_valid & ATTR_ATIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
  		attrs.ia_valid |= HOSTFS_ATTR_ATIME;
  		attrs.ia_atime = attr->ia_atime;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
798
  	if (attr->ia_valid & ATTR_MTIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
801
  		attrs.ia_valid |= HOSTFS_ATTR_MTIME;
  		attrs.ia_mtime = attr->ia_mtime;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
802
  	if (attr->ia_valid & ATTR_CTIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
  		attrs.ia_valid |= HOSTFS_ATTR_CTIME;
  		attrs.ia_ctime = attr->ia_ctime;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
806
  	if (attr->ia_valid & ATTR_ATIME_SET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
  		attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
809
  	if (attr->ia_valid & ATTR_MTIME_SET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  		attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
  	}
c5322220e   Al Viro   hostfs: get rid o...
812
  	name = dentry_name(dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
813
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
814
  		return -ENOMEM;
5822b7fac   Alberto Bertogli   uml: make hostfs_...
815
  	err = set_attr(name, &attrs, fd);
e9193059b   Al Viro   hostfs: fix races...
816
  	__putname(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
817
  	if (err)
f1adc05e7   Jeff Dike   uml: hostfs style...
818
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819

1025774ce   Christoph Hellwig   remove inode_setattr
820
  	if ((attr->ia_valid & ATTR_SIZE) &&
bc077320f   Marco Stornelli   hostfs: fix a not...
821
  	    attr->ia_size != i_size_read(inode))
3be2be0a3   Marco Stornelli   hostfs: drop vmtr...
822
  		truncate_setsize(inode, attr->ia_size);
1025774ce   Christoph Hellwig   remove inode_setattr
823
824
825
826
  
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  }
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
828
  static const struct inode_operations hostfs_iops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
  	.permission	= hostfs_permission,
  	.setattr	= hostfs_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
832
  static const struct inode_operations hostfs_dir_iops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
835
836
837
838
839
840
  	.create		= hostfs_create,
  	.lookup		= hostfs_lookup,
  	.link		= hostfs_link,
  	.unlink		= hostfs_unlink,
  	.symlink	= hostfs_symlink,
  	.mkdir		= hostfs_mkdir,
  	.rmdir		= hostfs_rmdir,
  	.mknod		= hostfs_mknod,
9a423bb6e   Miklos Szeredi   hostfs: support r...
841
  	.rename2	= hostfs_rename2,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
843
  	.permission	= hostfs_permission,
  	.setattr	= hostfs_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  };
d0352d3ed   Al Viro   hostfs: sanitize ...
845
846
847
848
849
850
851
  static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
  {
  	char *link = __getname();
  	if (link) {
  		char *path = dentry_name(dentry);
  		int err = -ENOMEM;
  		if (path) {
3b6036d14   Al Viro   hostfs ->follow_l...
852
  			err = hostfs_do_readlink(path, link, PATH_MAX);
d0352d3ed   Al Viro   hostfs: sanitize ...
853
854
  			if (err == PATH_MAX)
  				err = -E2BIG;
e9193059b   Al Viro   hostfs: fix races...
855
  			__putname(path);
d0352d3ed   Al Viro   hostfs: sanitize ...
856
857
858
859
860
861
862
  		}
  		if (err < 0) {
  			__putname(link);
  			link = ERR_PTR(err);
  		}
  	} else {
  		link = ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  	}
d0352d3ed   Al Viro   hostfs: sanitize ...
864
865
866
867
868
869
870
871
872
873
  
  	nd_set_link(nd, link);
  	return NULL;
  }
  
  static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
  {
  	char *s = nd_get_link(nd);
  	if (!IS_ERR(s))
  		__putname(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
  }
d0352d3ed   Al Viro   hostfs: sanitize ...
875
876
877
878
  static const struct inode_operations hostfs_link_iops = {
  	.readlink	= generic_readlink,
  	.follow_link	= hostfs_follow_link,
  	.put_link	= hostfs_put_link,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
880
881
882
883
  };
  
  static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
  {
  	struct inode *root_inode;
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
884
  	char *host_root_path, *req_root = d;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
888
889
890
  	int err;
  
  	sb->s_blocksize = 1024;
  	sb->s_blocksize_bits = 10;
  	sb->s_magic = HOSTFS_SUPER_MAGIC;
  	sb->s_op = &hostfs_sbops;
b26d4cd38   Al Viro   consolidate simpl...
891
  	sb->s_d_op = &simple_dentry_operations;
752fa51e4   Wolfgang Illmeyer   hostfs: set maxim...
892
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893

a6eb0be6d   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
894
  	/* NULL is printed as <NULL> by sprintf: avoid that. */
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
895
896
  	if (req_root == NULL)
  		req_root = "";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
  
  	err = -ENOMEM;
601d2c38b   Al Viro   hostfs: don't kee...
899
900
  	sb->s_fs_info = host_root_path =
  		kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
901
  	if (host_root_path == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
  		goto out;
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
903
  	sprintf(host_root_path, "%s/%s", root_ino, req_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904

52b209f7b   Al Viro   get rid of hostfs...
905
906
  	root_inode = new_inode(sb);
  	if (!root_inode)
601d2c38b   Al Viro   hostfs: don't kee...
907
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908

4754b8255   Al Viro   hostfs: get rid o...
909
910
911
  	err = read_name(root_inode, host_root_path);
  	if (err)
  		goto out_put;
52b209f7b   Al Viro   get rid of hostfs...
912

4754b8255   Al Viro   hostfs: get rid o...
913
  	if (S_ISLNK(root_inode->i_mode)) {
52b209f7b   Al Viro   get rid of hostfs...
914
915
916
917
918
919
  		char *name = follow_link(host_root_path);
  		if (IS_ERR(name))
  			err = PTR_ERR(name);
  		else
  			err = read_name(root_inode, name);
  		kfree(name);
4754b8255   Al Viro   hostfs: get rid o...
920
921
  		if (err)
  			goto out_put;
52b209f7b   Al Viro   get rid of hostfs...
922
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
  	err = -ENOMEM;
48fde701a   Al Viro   switch open-coded...
925
  	sb->s_root = d_make_root(root_inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
926
  	if (sb->s_root == NULL)
48fde701a   Al Viro   switch open-coded...
927
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928

f1adc05e7   Jeff Dike   uml: hostfs style...
929
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930

f1adc05e7   Jeff Dike   uml: hostfs style...
931
932
  out_put:
  	iput(root_inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
933
934
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
  }
3c26ff6e4   Al Viro   convert get_sb_no...
936
  static struct dentry *hostfs_read_sb(struct file_system_type *type,
454e2398b   David Howells   [PATCH] VFS: Perm...
937
  			  int flags, const char *dev_name,
3c26ff6e4   Al Viro   convert get_sb_no...
938
  			  void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  {
3c26ff6e4   Al Viro   convert get_sb_no...
940
  	return mount_nodev(type, flags, data, hostfs_fill_sb_common);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  }
601d2c38b   Al Viro   hostfs: don't kee...
942
943
944
945
946
  static void hostfs_kill_sb(struct super_block *s)
  {
  	kill_anon_super(s);
  	kfree(s->s_fs_info);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
  static struct file_system_type hostfs_type = {
  	.owner 		= THIS_MODULE,
  	.name 		= "hostfs",
3c26ff6e4   Al Viro   convert get_sb_no...
950
  	.mount	 	= hostfs_read_sb,
601d2c38b   Al Viro   hostfs: don't kee...
951
  	.kill_sb	= hostfs_kill_sb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  	.fs_flags 	= 0,
  };
3e64fe5b2   Eric W. Biederman   fs: Limit sys_mou...
954
  MODULE_ALIAS_FS("hostfs");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
956
957
  
  static int __init init_hostfs(void)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
958
  	return register_filesystem(&hostfs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
960
961
962
963
964
965
966
967
968
  }
  
  static void __exit exit_hostfs(void)
  {
  	unregister_filesystem(&hostfs_type);
  }
  
  module_init(init_hostfs)
  module_exit(exit_hostfs)
  MODULE_LICENSE("GPL");