Blame view

fs/hostfs/hostfs_kern.c 22.2 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/module.h>
84b3db04c   Jeff Dike   uml: fix hostfs s...
10
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/statfs.h>
dd2cc4dff   Miklos Szeredi   mount options: fi...
13
  #include <linux/seq_file.h>
6966a9775   Jiri Kosina   UML: fix hostfs b...
14
  #include <linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include "hostfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include "init.h"
84b3db04c   Jeff Dike   uml: fix hostfs s...
17
  #include "kern.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
  
  struct hostfs_inode_info {
  	char *host_filename;
  	int fd;
aeb5d7270   Al Viro   [PATCH] introduce...
22
  	fmode_t mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
  	struct inode vfs_inode;
  };
  
  static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
28
  	return list_entry(inode, struct hostfs_inode_info, vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  }
680b0da9b   Josef Sipek   [PATCH] struct pa...
30
  #define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

e16404ed0   Al Viro   constify dentry_o...
32
  static int hostfs_d_delete(struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
34
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  }
e16404ed0   Al Viro   constify dentry_o...
36
  static const struct dentry_operations hostfs_dentry_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
  	.d_delete		= hostfs_d_delete,
  };
  
  /* Changed in hostfs_args before the kernel starts running */
a6eb0be6d   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
41
  static char *root_ino = "";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  static int append = 0;
  
  #define HOSTFS_SUPER_MAGIC 0x00c0ffee
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
45
46
  static const struct inode_operations hostfs_iops;
  static const struct inode_operations hostfs_dir_iops;
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
47
  static const struct address_space_operations hostfs_link_aops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
52
53
54
  
  #ifndef MODULE
  static int __init hostfs_args(char *options, int *add)
  {
  	char *ptr;
  
  	ptr = strchr(options, ',');
84b3db04c   Jeff Dike   uml: fix hostfs s...
55
  	if (ptr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  		*ptr++ = '\0';
84b3db04c   Jeff Dike   uml: fix hostfs s...
57
  	if (*options != '\0')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
  		root_ino = options;
  
  	options = ptr;
84b3db04c   Jeff Dike   uml: fix hostfs s...
61
  	while (options) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  		ptr = strchr(options, ',');
84b3db04c   Jeff Dike   uml: fix hostfs s...
63
  		if (ptr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  			*ptr++ = '\0';
84b3db04c   Jeff Dike   uml: fix hostfs s...
65
66
  		if (*options != '\0') {
  			if (!strcmp(options, "append"))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
73
  				append = 1;
  			else printf("hostfs_args - unsupported option - %s
  ",
  				    options);
  		}
  		options = ptr;
  	}
f1adc05e7   Jeff Dike   uml: hostfs style...
74
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  }
  
  __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
  
  static char *dentry_name(struct dentry *dentry, int extra)
  {
  	struct dentry *parent;
  	char *root, *name;
  	int len;
  
  	len = 0;
  	parent = dentry;
84b3db04c   Jeff Dike   uml: fix hostfs s...
106
  	while (parent->d_parent != parent) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
112
113
  		len += parent->d_name.len + 1;
  		parent = parent->d_parent;
  	}
  
  	root = HOSTFS_I(parent->d_inode)->host_filename;
  	len += strlen(root);
  	name = kmalloc(len + extra + 1, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
114
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
115
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
  
  	name[len] = '\0';
  	parent = dentry;
84b3db04c   Jeff Dike   uml: fix hostfs s...
119
  	while (parent->d_parent != parent) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
123
124
125
126
  		len -= parent->d_name.len + 1;
  		name[len] = '/';
  		strncpy(&name[len + 1], parent->d_name.name,
  			parent->d_name.len);
  		parent = parent->d_parent;
  	}
  	strncpy(name, root, strlen(root));
f1adc05e7   Jeff Dike   uml: hostfs style...
127
  	return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
132
133
134
  }
  
  static char *inode_name(struct inode *ino, int extra)
  {
  	struct dentry *dentry;
  
  	dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
f1adc05e7   Jeff Dike   uml: hostfs style...
135
  	return dentry_name(dentry, extra);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
  }
  
  static int read_name(struct inode *ino, char *name)
  {
84b3db04c   Jeff Dike   uml: fix hostfs s...
140
141
  	/*
  	 * The non-int inode fields are copied into ints by stat_file and
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
147
148
149
150
151
152
  	 * then copied into the inode because passing the actual pointers
  	 * in and having them treated as int * breaks on big-endian machines
  	 */
  	int err;
  	int i_mode, i_nlink, i_blksize;
  	unsigned long long i_size;
  	unsigned long long i_ino;
  	unsigned long long i_blocks;
  
  	err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
  			&ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
5822b7fac   Alberto Bertogli   uml: make hostfs_...
153
  			&ino->i_ctime, &i_blksize, &i_blocks, -1);
84b3db04c   Jeff Dike   uml: fix hostfs s...
154
  	if (err)
f1adc05e7   Jeff Dike   uml: hostfs style...
155
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
  
  	ino->i_ino = i_ino;
  	ino->i_mode = i_mode;
  	ino->i_nlink = i_nlink;
  	ino->i_size = i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  	ino->i_blocks = i_blocks;
f1adc05e7   Jeff Dike   uml: hostfs style...
162
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
170
  }
  
  static char *follow_link(char *link)
  {
  	int len, n;
  	char *name, *resolved, *end;
  
  	len = 64;
84b3db04c   Jeff Dike   uml: fix hostfs s...
171
  	while (1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
  		n = -ENOMEM;
  		name = kmalloc(len, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
174
  		if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  			goto out;
ea7e743e4   WANG Cong   hostfs: fix a dup...
176
  		n = hostfs_do_readlink(link, name, len);
84b3db04c   Jeff Dike   uml: fix hostfs s...
177
  		if (n < len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
181
  			break;
  		len *= 2;
  		kfree(name);
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
182
  	if (n < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  		goto out_free;
84b3db04c   Jeff Dike   uml: fix hostfs s...
184
  	if (*name == '/')
f1adc05e7   Jeff Dike   uml: hostfs style...
185
  		return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
  
  	end = strrchr(link, '/');
84b3db04c   Jeff Dike   uml: fix hostfs s...
188
  	if (end == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
189
  		return name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
  
  	*(end + 1) = '\0';
  	len = strlen(link) + strlen(name) + 1;
  
  	resolved = kmalloc(len, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
195
  	if (resolved == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
200
201
202
  		n = -ENOMEM;
  		goto out_free;
  	}
  
  	sprintf(resolved, "%s%s", link, name);
  	kfree(name);
  	kfree(link);
f1adc05e7   Jeff Dike   uml: hostfs style...
203
  	return resolved;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
207
  
   out_free:
  	kfree(name);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
208
  	return ERR_PTR(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
  }
0a370e5de   David Howells   iget: stop HOSTFS...
210
  static int hostfs_read_inode(struct inode *ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
  {
  	char *name;
  	int err = 0;
84b3db04c   Jeff Dike   uml: fix hostfs s...
214
215
  	/*
  	 * Unfortunately, we are called from iget() when we don't have a dentry
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
  	 * allocated yet.
  	 */
84b3db04c   Jeff Dike   uml: fix hostfs s...
218
  	if (list_empty(&ino->i_dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
  		goto out;
  
  	err = -ENOMEM;
  	name = inode_name(ino, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
223
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  		goto out;
84b3db04c   Jeff Dike   uml: fix hostfs s...
225
  	if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  		name = follow_link(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
227
  		if (IS_ERR(name)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
233
234
235
  			err = PTR_ERR(name);
  			goto out;
  		}
  	}
  
  	err = read_name(ino, name);
  	kfree(name);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
236
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  }
0a370e5de   David Howells   iget: stop HOSTFS...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  static struct inode *hostfs_iget(struct super_block *sb)
  {
  	struct inode *inode;
  	long ret;
  
  	inode = iget_locked(sb, 0);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  	if (inode->i_state & I_NEW) {
  		ret = hostfs_read_inode(inode);
  		if (ret < 0) {
  			iget_failed(inode);
  			return ERR_PTR(ret);
  		}
  		unlock_new_inode(inode);
  	}
  	return inode;
  }
726c33422   David Howells   [PATCH] VFS: Perm...
256
  int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  {
84b3db04c   Jeff Dike   uml: fix hostfs s...
258
259
  	/*
  	 * do_statfs uses struct statfs64 internally, but the linux kernel
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
263
264
265
266
267
268
  	 * 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;
726c33422   David Howells   [PATCH] VFS: Perm...
269
  	err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
  			&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
  			&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
  			&sf->f_namelen, sf->f_spare);
84b3db04c   Jeff Dike   uml: fix hostfs s...
273
  	if (err)
f1adc05e7   Jeff Dike   uml: hostfs style...
274
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
278
279
280
  	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...
281
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
286
287
288
  }
  
  static struct inode *hostfs_alloc_inode(struct super_block *sb)
  {
  	struct hostfs_inode_info *hi;
  
  	hi = kmalloc(sizeof(*hi), GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
289
  	if (hi == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
290
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
  
  	*hi = ((struct hostfs_inode_info) { .host_filename	= NULL,
  					    .fd			= -1,
  					    .mode		= 0 });
  	inode_init_once(&hi->vfs_inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
296
  	return &hi->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
  }
  
  static void hostfs_delete_inode(struct inode *inode)
  {
fef266580   Mark Fasheh   [PATCH] update fi...
301
  	truncate_inode_pages(&inode->i_data, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
302
  	if (HOSTFS_I(inode)->fd != -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
307
308
309
310
  		close_file(&HOSTFS_I(inode)->fd);
  		HOSTFS_I(inode)->fd = -1;
  	}
  	clear_inode(inode);
  }
  
  static void hostfs_destroy_inode(struct inode *inode)
  {
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
311
  	kfree(HOSTFS_I(inode)->host_filename);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312

84b3db04c   Jeff Dike   uml: fix hostfs s...
313
314
315
316
317
  	/*
  	 * XXX: This should not happen, probably. The check is here for
  	 * additional safety.
  	 */
  	if (HOSTFS_I(inode)->fd != -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
324
  		close_file(&HOSTFS_I(inode)->fd);
  		printk(KERN_DEBUG "Closing host fd in .destroy_inode
  ");
  	}
  
  	kfree(HOSTFS_I(inode));
  }
dd2cc4dff   Miklos Szeredi   mount options: fi...
325
326
327
328
329
330
331
332
333
334
335
  static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
  {
  	struct inode *root = vfs->mnt_sb->s_root->d_inode;
  	const char *root_path = HOSTFS_I(root)->host_filename;
  	size_t offset = strlen(root_ino) + 1;
  
  	if (strlen(root_path) > offset)
  		seq_printf(seq, ",%s", root_path + offset);
  
  	return 0;
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
336
  static const struct super_operations hostfs_sbops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
  	.alloc_inode	= hostfs_alloc_inode,
  	.drop_inode	= generic_delete_inode,
  	.delete_inode   = hostfs_delete_inode,
  	.destroy_inode	= hostfs_destroy_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
  	.statfs		= hostfs_statfs,
dd2cc4dff   Miklos Szeredi   mount options: fi...
342
  	.show_options	= hostfs_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
347
348
349
350
  };
  
  int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
  {
  	void *dir;
  	char *name;
  	unsigned long long next, ino;
  	int error, len;
680b0da9b   Josef Sipek   [PATCH] struct pa...
351
  	name = dentry_name(file->f_path.dentry, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
352
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
353
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
  	dir = open_dir(name, &error);
  	kfree(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
356
  	if (dir == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
357
  		return -error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  	next = file->f_pos;
84b3db04c   Jeff Dike   uml: fix hostfs s...
359
  	while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
  		error = (*filldir)(ent, name, len, file->f_pos,
  				   ino, DT_UNKNOWN);
84b3db04c   Jeff Dike   uml: fix hostfs s...
362
  		if (error) break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
  		file->f_pos = next;
  	}
  	close_dir(dir);
f1adc05e7   Jeff Dike   uml: hostfs style...
366
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
  }
  
  int hostfs_file_open(struct inode *ino, struct file *file)
  {
  	char *name;
aeb5d7270   Al Viro   [PATCH] introduce...
372
373
  	fmode_t mode = 0;
  	int r = 0, w = 0, fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
  
  	mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
84b3db04c   Jeff Dike   uml: fix hostfs s...
376
  	if ((mode & HOSTFS_I(ino)->mode) == mode)
f1adc05e7   Jeff Dike   uml: hostfs style...
377
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

84b3db04c   Jeff Dike   uml: fix hostfs s...
379
380
  	/*
  	 * The file may already have been opened, but with the wrong access,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
  	 * so this resets things and reopens the file with the new access.
  	 */
84b3db04c   Jeff Dike   uml: fix hostfs s...
383
  	if (HOSTFS_I(ino)->fd != -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
  		close_file(&HOSTFS_I(ino)->fd);
  		HOSTFS_I(ino)->fd = -1;
  	}
  
  	HOSTFS_I(ino)->mode |= mode;
84b3db04c   Jeff Dike   uml: fix hostfs s...
389
  	if (HOSTFS_I(ino)->mode & FMODE_READ)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  		r = 1;
84b3db04c   Jeff Dike   uml: fix hostfs s...
391
  	if (HOSTFS_I(ino)->mode & FMODE_WRITE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  		w = 1;
84b3db04c   Jeff Dike   uml: fix hostfs s...
393
  	if (w)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  		r = 1;
680b0da9b   Josef Sipek   [PATCH] struct pa...
395
  	name = dentry_name(file->f_path.dentry, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
396
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
397
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
  
  	fd = open_file(name, r, w, append);
  	kfree(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
401
  	if (fd < 0)
f1adc05e7   Jeff Dike   uml: hostfs style...
402
  		return fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  	FILE_HOSTFS_I(file)->fd = fd;
f1adc05e7   Jeff Dike   uml: hostfs style...
404
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
408
  }
  
  int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
  {
a2d76bd8f   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: impl...
409
  	return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
411
  static const struct file_operations hostfs_file_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  	.llseek		= generic_file_llseek,
543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
413
  	.read		= do_sync_read,
5ffc4ef45   Jens Axboe   sendfile: remove ...
414
  	.splice_read	= generic_file_splice_read,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
  	.aio_read	= generic_file_aio_read,
  	.aio_write	= generic_file_aio_write,
543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
417
  	.write		= do_sync_write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
422
  	.mmap		= generic_file_mmap,
  	.open		= hostfs_file_open,
  	.release	= NULL,
  	.fsync		= hostfs_fsync,
  };
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
423
  static const struct file_operations hostfs_dir_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  	.llseek		= generic_file_llseek,
  	.readdir	= hostfs_readdir,
  	.read		= generic_read_dir,
  };
  
  int hostfs_writepage(struct page *page, struct writeback_control *wbc)
  {
  	struct address_space *mapping = page->mapping;
  	struct inode *inode = mapping->host;
  	char *buffer;
  	unsigned long long base;
  	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);
  	base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
  
  	err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
84b3db04c   Jeff Dike   uml: fix hostfs s...
446
  	if (err != count) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  		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;
  }
  
  int hostfs_readpage(struct file *file, struct page *page)
  {
  	char *buffer;
  	long long start;
  	int err = 0;
  
  	start = (long long) page->index << PAGE_CACHE_SHIFT;
  	buffer = kmap(page);
  	err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
  			PAGE_CACHE_SIZE);
84b3db04c   Jeff Dike   uml: fix hostfs s...
475
476
  	if (err < 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
486
  
  	memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
  
  	flush_dcache_page(page);
  	SetPageUptodate(page);
  	if (PageError(page)) ClearPageError(page);
  	err = 0;
   out:
  	kunmap(page);
  	unlock_page(page);
f1adc05e7   Jeff Dike   uml: hostfs style...
487
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  }
ae361ff46   Nick Piggin   hostfs: convert t...
489
490
491
  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
492
  {
ae361ff46   Nick Piggin   hostfs: convert t...
493
  	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494

54566b2c1   Nick Piggin   fs: symlink write...
495
  	*pagep = grab_cache_page_write_begin(mapping, index, flags);
ae361ff46   Nick Piggin   hostfs: convert t...
496
497
498
  	if (!*pagep)
  		return -ENOMEM;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
  }
ae361ff46   Nick Piggin   hostfs: convert t...
500
501
502
  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
503
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
  	struct inode *inode = mapping->host;
ae361ff46   Nick Piggin   hostfs: convert t...
505
506
507
  	void *buffer;
  	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508

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

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

84b3db04c   Jeff Dike   uml: fix hostfs s...
516
517
  	/*
  	 * If err > 0, write_file has added err to pos, so we are comparing
ae361ff46   Nick Piggin   hostfs: convert t...
518
519
520
521
522
523
  	 * 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
524

f1adc05e7   Jeff Dike   uml: hostfs style...
525
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
527
  static const struct address_space_operations hostfs_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
  	.writepage 	= hostfs_writepage,
  	.readpage	= hostfs_readpage,
ffa0aea68   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml - hos...
530
  	.set_page_dirty = __set_page_dirty_nobuffers,
ae361ff46   Nick Piggin   hostfs: convert t...
531
532
  	.write_begin	= hostfs_write_begin,
  	.write_end	= hostfs_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
537
538
539
540
  };
  
  static int init_inode(struct inode *inode, struct dentry *dentry)
  {
  	char *name;
  	int type, err = -ENOMEM;
  	int maj, min;
  	dev_t rdev = 0;
84b3db04c   Jeff Dike   uml: fix hostfs s...
541
  	if (dentry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  		name = dentry_name(dentry, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
543
  		if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
  			goto out;
  		type = file_type(name, &maj, &min);
84b3db04c   Jeff Dike   uml: fix hostfs s...
546
  		/* Reencode maj and min with the kernel encoding.*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
549
550
551
552
  		rdev = MKDEV(maj, min);
  		kfree(name);
  	}
  	else type = OS_TYPE_DIR;
  
  	err = 0;
84b3db04c   Jeff Dike   uml: fix hostfs s...
553
  	if (type == OS_TYPE_SYMLINK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  		inode->i_op = &page_symlink_inode_operations;
84b3db04c   Jeff Dike   uml: fix hostfs s...
555
  	else if (type == OS_TYPE_DIR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
  		inode->i_op = &hostfs_dir_iops;
  	else inode->i_op = &hostfs_iops;
84b3db04c   Jeff Dike   uml: fix hostfs s...
558
  	if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  	else inode->i_fop = &hostfs_file_fops;
84b3db04c   Jeff Dike   uml: fix hostfs s...
560
  	if (type == OS_TYPE_SYMLINK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  		inode->i_mapping->a_ops = &hostfs_link_aops;
  	else inode->i_mapping->a_ops = &hostfs_aops;
  
  	switch (type) {
  	case OS_TYPE_CHARDEV:
  		init_special_inode(inode, S_IFCHR, rdev);
  		break;
  	case OS_TYPE_BLOCKDEV:
  		init_special_inode(inode, S_IFBLK, rdev);
  		break;
  	case OS_TYPE_FIFO:
  		init_special_inode(inode, S_IFIFO, 0);
  		break;
  	case OS_TYPE_SOCK:
  		init_special_inode(inode, S_IFSOCK, 0);
  		break;
  	}
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
579
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
  }
  
  int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
84b3db04c   Jeff Dike   uml: fix hostfs s...
583
  		  struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
587
  {
  	struct inode *inode;
  	char *name;
  	int error, fd;
0a370e5de   David Howells   iget: stop HOSTFS...
588
589
590
  	inode = hostfs_iget(dir->i_sb);
  	if (IS_ERR(inode)) {
  		error = PTR_ERR(inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
591
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
592
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
  
  	error = init_inode(inode, dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
595
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
598
599
  		goto out_put;
  
  	error = -ENOMEM;
  	name = dentry_name(dentry, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
600
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
604
605
606
  		goto out_put;
  
  	fd = file_create(name,
  			 mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
  			 mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
  			 mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
84b3db04c   Jeff Dike   uml: fix hostfs s...
607
  	if (fd < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
611
  		error = fd;
  	else error = read_name(inode, name);
  
  	kfree(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
612
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
617
  		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...
618
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
620
621
622
  
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
623
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
  }
  
  struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
f1adc05e7   Jeff Dike   uml: hostfs style...
627
  			     struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
631
  {
  	struct inode *inode;
  	char *name;
  	int err;
0a370e5de   David Howells   iget: stop HOSTFS...
632
633
634
  	inode = hostfs_iget(ino->i_sb);
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
636
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
  
  	err = init_inode(inode, dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
639
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
  		goto out_put;
  
  	err = -ENOMEM;
  	name = dentry_name(dentry, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
644
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
  		goto out_put;
  
  	err = read_name(inode, name);
  	kfree(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
649
  	if (err == -ENOENT) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
  		iput(inode);
  		inode = NULL;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
653
  	else if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
  		goto out_put;
  
  	d_add(dentry, inode);
  	dentry->d_op = &hostfs_dentry_ops;
f1adc05e7   Jeff Dike   uml: hostfs style...
658
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
  
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
663
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
  }
  
  static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
668
  	char *file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
  	int len;
  
  	file = inode_name(ino, dentry->d_name.len + 1);
84b3db04c   Jeff Dike   uml: fix hostfs s...
672
  	if (file == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
673
674
  		return NULL;
  	strcat(file, "/");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
  	len = strlen(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
676
  	strncat(file, dentry->d_name.name, dentry->d_name.len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  	file[len + dentry->d_name.len] = '\0';
f1adc05e7   Jeff Dike   uml: hostfs style...
678
  	return file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
682
  }
  
  int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
683
684
  	char *from_name, *to_name;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685

84b3db04c   Jeff Dike   uml: fix hostfs s...
686
  	if ((from_name = inode_dentry_name(ino, from)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
687
688
  		return -ENOMEM;
  	to_name = dentry_name(to, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
689
  	if (to_name == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
  		kfree(from_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
691
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  	}
f1adc05e7   Jeff Dike   uml: hostfs style...
693
694
695
696
  	err = link_file(to_name, from_name);
  	kfree(from_name);
  	kfree(to_name);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
700
701
702
  }
  
  int hostfs_unlink(struct inode *ino, struct dentry *dentry)
  {
  	char *file;
  	int err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
703
  	if ((file = inode_dentry_name(ino, dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
704
  		return -ENOMEM;
84b3db04c   Jeff Dike   uml: fix hostfs s...
705
  	if (append)
f1adc05e7   Jeff Dike   uml: hostfs style...
706
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
  
  	err = unlink_file(file);
  	kfree(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
710
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
714
715
716
  }
  
  int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
  {
  	char *file;
  	int err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
717
  	if ((file = inode_dentry_name(ino, dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
718
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
  	err = make_symlink(file, to);
  	kfree(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
721
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
726
727
  }
  
  int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
  {
  	char *file;
  	int err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
728
  	if ((file = inode_dentry_name(ino, dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
729
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
  	err = do_mkdir(file, mode);
  	kfree(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
732
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
736
737
738
  }
  
  int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
  {
  	char *file;
  	int err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
739
  	if ((file = inode_dentry_name(ino, dentry)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
740
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
  	err = do_rmdir(file);
  	kfree(file);
f1adc05e7   Jeff Dike   uml: hostfs style...
743
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
747
748
749
  }
  
  int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
  {
  	struct inode *inode;
  	char *name;
0a370e5de   David Howells   iget: stop HOSTFS...
750
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751

0a370e5de   David Howells   iget: stop HOSTFS...
752
753
754
  	inode = hostfs_iget(dir->i_sb);
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  		goto out;
0a370e5de   David Howells   iget: stop HOSTFS...
756
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
  
  	err = init_inode(inode, dentry);
84b3db04c   Jeff Dike   uml: fix hostfs s...
759
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
762
763
  		goto out_put;
  
  	err = -ENOMEM;
  	name = dentry_name(dentry, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
764
  	if (name == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
  		goto out_put;
  
  	init_special_inode(inode, mode, dev);
88f6cd0c3   Johannes Stezenbach   [PATCH] uml: fix ...
768
  	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
84b3db04c   Jeff Dike   uml: fix hostfs s...
769
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
772
773
  		goto out_free;
  
  	err = read_name(inode, name);
  	kfree(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
774
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
  		goto out_put;
  
  	d_instantiate(dentry, inode);
f1adc05e7   Jeff Dike   uml: hostfs style...
778
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
782
783
784
  
   out_free:
  	kfree(name);
   out_put:
  	iput(inode);
   out:
f1adc05e7   Jeff Dike   uml: hostfs style...
785
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
792
  }
  
  int hostfs_rename(struct inode *from_ino, struct dentry *from,
  		  struct inode *to_ino, struct dentry *to)
  {
  	char *from_name, *to_name;
  	int err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
793
  	if ((from_name = inode_dentry_name(from_ino, from)) == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
794
  		return -ENOMEM;
84b3db04c   Jeff Dike   uml: fix hostfs s...
795
  	if ((to_name = inode_dentry_name(to_ino, to)) == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
  		kfree(from_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
797
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
801
  	}
  	err = rename_file(from_name, to_name);
  	kfree(from_name);
  	kfree(to_name);
f1adc05e7   Jeff Dike   uml: hostfs style...
802
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
  }
e6305c43e   Al Viro   [PATCH] sanitize ...
804
  int hostfs_permission(struct inode *ino, int desired)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
806
807
808
809
810
811
812
  {
  	char *name;
  	int r = 0, w = 0, x = 0, err;
  
  	if (desired & MAY_READ) r = 1;
  	if (desired & MAY_WRITE) w = 1;
  	if (desired & MAY_EXEC) x = 1;
  	name = inode_name(ino, 0);
f1adc05e7   Jeff Dike   uml: hostfs style...
813
814
  	if (name == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
  
  	if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
84b3db04c   Jeff Dike   uml: fix hostfs s...
817
  	    S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
820
821
  		err = 0;
  	else
  		err = access_file(name, r, w, x);
  	kfree(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
822
  	if (!err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
825
826
827
828
829
830
831
  		err = generic_permission(ino, desired, NULL);
  	return err;
  }
  
  int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
  {
  	struct hostfs_iattr attrs;
  	char *name;
  	int err;
5822b7fac   Alberto Bertogli   uml: make hostfs_...
832
  	int fd = HOSTFS_I(dentry->d_inode)->fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
835
  	err = inode_change_ok(dentry->d_inode, attr);
  	if (err)
  		return err;
84b3db04c   Jeff Dike   uml: fix hostfs s...
836
  	if (append)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
  		attr->ia_valid &= ~ATTR_SIZE;
  
  	attrs.ia_valid = 0;
84b3db04c   Jeff Dike   uml: fix hostfs s...
840
  	if (attr->ia_valid & ATTR_MODE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
843
  		attrs.ia_valid |= HOSTFS_ATTR_MODE;
  		attrs.ia_mode = attr->ia_mode;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
844
  	if (attr->ia_valid & ATTR_UID) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
  		attrs.ia_valid |= HOSTFS_ATTR_UID;
  		attrs.ia_uid = attr->ia_uid;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
848
  	if (attr->ia_valid & ATTR_GID) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
850
851
  		attrs.ia_valid |= HOSTFS_ATTR_GID;
  		attrs.ia_gid = attr->ia_gid;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
852
  	if (attr->ia_valid & ATTR_SIZE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
  		attrs.ia_valid |= HOSTFS_ATTR_SIZE;
  		attrs.ia_size = attr->ia_size;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
856
  	if (attr->ia_valid & ATTR_ATIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
858
859
  		attrs.ia_valid |= HOSTFS_ATTR_ATIME;
  		attrs.ia_atime = attr->ia_atime;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
860
  	if (attr->ia_valid & ATTR_MTIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
863
  		attrs.ia_valid |= HOSTFS_ATTR_MTIME;
  		attrs.ia_mtime = attr->ia_mtime;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
864
  	if (attr->ia_valid & ATTR_CTIME) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
867
  		attrs.ia_valid |= HOSTFS_ATTR_CTIME;
  		attrs.ia_ctime = attr->ia_ctime;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
868
  	if (attr->ia_valid & ATTR_ATIME_SET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
  		attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
  	}
84b3db04c   Jeff Dike   uml: fix hostfs s...
871
  	if (attr->ia_valid & ATTR_MTIME_SET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
  		attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
  	}
  	name = dentry_name(dentry, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
875
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
876
  		return -ENOMEM;
5822b7fac   Alberto Bertogli   uml: make hostfs_...
877
  	err = set_attr(name, &attrs, fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  	kfree(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
879
  	if (err)
f1adc05e7   Jeff Dike   uml: hostfs style...
880
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881

f1adc05e7   Jeff Dike   uml: hostfs style...
882
  	return inode_setattr(dentry->d_inode, attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
  }
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
884
  static const struct inode_operations hostfs_iops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
888
889
890
891
892
  	.create		= hostfs_create,
  	.link		= hostfs_link,
  	.unlink		= hostfs_unlink,
  	.symlink	= hostfs_symlink,
  	.mkdir		= hostfs_mkdir,
  	.rmdir		= hostfs_rmdir,
  	.mknod		= hostfs_mknod,
  	.rename		= hostfs_rename,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
  	.permission	= hostfs_permission,
  	.setattr	= hostfs_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
896
  static const struct inode_operations hostfs_dir_iops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
901
902
903
904
905
  	.create		= hostfs_create,
  	.lookup		= hostfs_lookup,
  	.link		= hostfs_link,
  	.unlink		= hostfs_unlink,
  	.symlink	= hostfs_symlink,
  	.mkdir		= hostfs_mkdir,
  	.rmdir		= hostfs_rmdir,
  	.mknod		= hostfs_mknod,
  	.rename		= hostfs_rename,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
  	.permission	= hostfs_permission,
  	.setattr	= hostfs_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
912
  };
  
  int hostfs_link_readpage(struct file *file, struct page *page)
  {
  	char *buffer, *name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
  	buffer = kmap(page);
  	name = inode_name(page->mapping->host, 0);
84b3db04c   Jeff Dike   uml: fix hostfs s...
916
  	if (name == NULL)
f1adc05e7   Jeff Dike   uml: hostfs style...
917
  		return -ENOMEM;
ea7e743e4   WANG Cong   hostfs: fix a dup...
918
  	err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
  	kfree(name);
84b3db04c   Jeff Dike   uml: fix hostfs s...
920
  	if (err == PAGE_CACHE_SIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
  		err = -E2BIG;
84b3db04c   Jeff Dike   uml: fix hostfs s...
922
  	else if (err > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
925
926
927
928
929
  		flush_dcache_page(page);
  		SetPageUptodate(page);
  		if (PageError(page)) ClearPageError(page);
  		err = 0;
  	}
  	kunmap(page);
  	unlock_page(page);
f1adc05e7   Jeff Dike   uml: hostfs style...
930
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
932
  static const struct address_space_operations hostfs_link_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
936
937
938
  	.readpage	= hostfs_link_readpage,
  };
  
  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...
939
  	char *host_root_path, *req_root = d;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
942
943
944
945
  	int err;
  
  	sb->s_blocksize = 1024;
  	sb->s_blocksize_bits = 10;
  	sb->s_magic = HOSTFS_SUPER_MAGIC;
  	sb->s_op = &hostfs_sbops;
752fa51e4   Wolfgang Illmeyer   hostfs: set maxim...
946
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947

a6eb0be6d   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
948
  	/* NULL is printed as <NULL> by sprintf: avoid that. */
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
949
950
  	if (req_root == NULL)
  		req_root = "";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
  
  	err = -ENOMEM;
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
953
954
  	host_root_path = kmalloc(strlen(root_ino) + 1
  				 + strlen(req_root) + 1, GFP_KERNEL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
955
  	if (host_root_path == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
  		goto out;
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
957
  	sprintf(host_root_path, "%s/%s", root_ino, req_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958

0a370e5de   David Howells   iget: stop HOSTFS...
959
960
961
  	root_inode = hostfs_iget(sb);
  	if (IS_ERR(root_inode)) {
  		err = PTR_ERR(root_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
  		goto out_free;
0a370e5de   David Howells   iget: stop HOSTFS...
963
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
965
  
  	err = init_inode(root_inode, NULL);
84b3db04c   Jeff Dike   uml: fix hostfs s...
966
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
  		goto out_put;
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
968
  	HOSTFS_I(root_inode)->host_filename = host_root_path;
84b3db04c   Jeff Dike   uml: fix hostfs s...
969
970
971
972
  	/*
  	 * Avoid that in the error path, iput(root_inode) frees again
  	 * host_root_path through hostfs_destroy_inode!
  	 */
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
973
  	host_root_path = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
976
  
  	err = -ENOMEM;
  	sb->s_root = d_alloc_root(root_inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
977
  	if (sb->s_root == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
  		goto out_put;
0a370e5de   David Howells   iget: stop HOSTFS...
979
  	err = hostfs_read_inode(root_inode);
84b3db04c   Jeff Dike   uml: fix hostfs s...
980
  	if (err) {
f1adc05e7   Jeff Dike   uml: hostfs style...
981
982
983
  		/* No iput in this case because the dput does that for us */
  		dput(sb->s_root);
  		sb->s_root = NULL;
bca271136   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
984
  		goto out;
f1adc05e7   Jeff Dike   uml: hostfs style...
985
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986

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

f1adc05e7   Jeff Dike   uml: hostfs style...
989
990
991
  out_put:
  	iput(root_inode);
  out_free:
75e8defbe   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: host...
992
  	kfree(host_root_path);
f1adc05e7   Jeff Dike   uml: hostfs style...
993
994
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  }
454e2398b   David Howells   [PATCH] VFS: Perm...
996
997
998
  static int hostfs_read_sb(struct file_system_type *type,
  			  int flags, const char *dev_name,
  			  void *data, struct vfsmount *mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
  {
454e2398b   David Howells   [PATCH] VFS: Perm...
1000
  	return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
  }
  
  static struct file_system_type hostfs_type = {
  	.owner 		= THIS_MODULE,
  	.name 		= "hostfs",
  	.get_sb 	= hostfs_read_sb,
  	.kill_sb	= kill_anon_super,
  	.fs_flags 	= 0,
  };
  
  static int __init init_hostfs(void)
  {
f1adc05e7   Jeff Dike   uml: hostfs style...
1013
  	return register_filesystem(&hostfs_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
  }
  
  static void __exit exit_hostfs(void)
  {
  	unregister_filesystem(&hostfs_type);
  }
  
  module_init(init_hostfs)
  module_exit(exit_hostfs)
  MODULE_LICENSE("GPL");