hostfs_kern.c 20.3 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
J
Jeff Dike 已提交
2
 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
L
Linus Torvalds 已提交
3 4 5 6 7 8 9
 * Licensed under the GPL
 *
 * Ported the filesystem routines to 2.5.
 * 2003-02-10 Petr Baudis <pasky@ucw.cz>
 */

#include <linux/fs.h>
10
#include <linux/magic.h>
L
Linus Torvalds 已提交
11
#include <linux/module.h>
J
Jeff Dike 已提交
12
#include <linux/mm.h>
L
Linus Torvalds 已提交
13 14
#include <linux/pagemap.h>
#include <linux/statfs.h>
15
#include <linux/slab.h>
M
Miklos Szeredi 已提交
16
#include <linux/seq_file.h>
J
Jiri Kosina 已提交
17
#include <linux/mount.h>
A
Al Viro 已提交
18
#include <linux/namei.h>
L
Linus Torvalds 已提交
19
#include "hostfs.h"
20 21
#include <init.h>
#include <kern.h>
L
Linus Torvalds 已提交
22 23 24

struct hostfs_inode_info {
	int fd;
25
	fmode_t mode;
L
Linus Torvalds 已提交
26 27 28 29 30
	struct inode vfs_inode;
};

static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
{
J
Jeff Dike 已提交
31
	return list_entry(inode, struct hostfs_inode_info, vfs_inode);
L
Linus Torvalds 已提交
32 33
}

A
Al Viro 已提交
34
#define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file))
L
Linus Torvalds 已提交
35 36

/* Changed in hostfs_args before the kernel starts running */
37
static char *root_ino = "";
L
Linus Torvalds 已提交
38 39
static int append = 0;

40 41
static const struct inode_operations hostfs_iops;
static const struct inode_operations hostfs_dir_iops;
A
Al Viro 已提交
42
static const struct inode_operations hostfs_link_iops;
L
Linus Torvalds 已提交
43 44 45 46 47 48 49

#ifndef MODULE
static int __init hostfs_args(char *options, int *add)
{
	char *ptr;

	ptr = strchr(options, ',');
J
Jeff Dike 已提交
50
	if (ptr != NULL)
L
Linus Torvalds 已提交
51
		*ptr++ = '\0';
J
Jeff Dike 已提交
52
	if (*options != '\0')
L
Linus Torvalds 已提交
53 54 55
		root_ino = options;

	options = ptr;
J
Jeff Dike 已提交
56
	while (options) {
L
Linus Torvalds 已提交
57
		ptr = strchr(options, ',');
J
Jeff Dike 已提交
58
		if (ptr != NULL)
L
Linus Torvalds 已提交
59
			*ptr++ = '\0';
J
Jeff Dike 已提交
60 61
		if (*options != '\0') {
			if (!strcmp(options, "append"))
L
Linus Torvalds 已提交
62 63 64 65 66 67
				append = 1;
			else printf("hostfs_args - unsupported option - %s\n",
				    options);
		}
		options = ptr;
	}
J
Jeff Dike 已提交
68
	return 0;
L
Linus Torvalds 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82
}

__uml_setup("hostfs=", hostfs_args,
"hostfs=<root dir>,<flags>,...\n"
"    This is used to set hostfs parameters.  The root directory argument\n"
"    is used to confine all hostfs mounts to within the specified directory\n"
"    tree on the host.  If this isn't specified, then a user inside UML can\n"
"    mount anything on the host that's accessible to the user that's running\n"
"    it.\n"
"    The only flag currently supported is 'append', which specifies that all\n"
"    files opened by hostfs will be opened in append mode.\n\n"
);
#endif

83
static char *__dentry_name(struct dentry *dentry, char *name)
L
Linus Torvalds 已提交
84
{
N
Nick Piggin 已提交
85
	char *p = dentry_path_raw(dentry, name, PATH_MAX);
86 87
	char *root;
	size_t len;
L
Linus Torvalds 已提交
88

89 90 91 92
	root = dentry->d_sb->s_fs_info;
	len = strlen(root);
	if (IS_ERR(p)) {
		__putname(name);
J
Jeff Dike 已提交
93
		return NULL;
L
Linus Torvalds 已提交
94
	}
95
	strlcpy(name, root, PATH_MAX);
96 97 98 99 100 101 102 103 104
	if (len > p - name) {
		__putname(name);
		return NULL;
	}
	if (p > name + len) {
		char *s = name + len;
		while ((*s++ = *p++) != '\0')
			;
	}
J
Jeff Dike 已提交
105
	return name;
L
Linus Torvalds 已提交
106 107
}

108 109 110 111 112 113
static char *dentry_name(struct dentry *dentry)
{
	char *name = __getname();
	if (!name)
		return NULL;

114
	return __dentry_name(dentry, name);
115 116
}

A
Al Viro 已提交
117
static char *inode_name(struct inode *ino)
L
Linus Torvalds 已提交
118 119
{
	struct dentry *dentry;
N
Nick Piggin 已提交
120
	char *name;
L
Linus Torvalds 已提交
121

N
Nick Piggin 已提交
122 123
	dentry = d_find_alias(ino);
	if (!dentry)
124
		return NULL;
N
Nick Piggin 已提交
125 126 127 128 129 130

	name = dentry_name(dentry);

	dput(dentry);

	return name;
L
Linus Torvalds 已提交
131 132 133 134 135 136 137 138
}

static char *follow_link(char *link)
{
	int len, n;
	char *name, *resolved, *end;

	len = 64;
J
Jeff Dike 已提交
139
	while (1) {
L
Linus Torvalds 已提交
140 141
		n = -ENOMEM;
		name = kmalloc(len, GFP_KERNEL);
J
Jeff Dike 已提交
142
		if (name == NULL)
L
Linus Torvalds 已提交
143 144
			goto out;

145
		n = hostfs_do_readlink(link, name, len);
J
Jeff Dike 已提交
146
		if (n < len)
L
Linus Torvalds 已提交
147 148 149 150
			break;
		len *= 2;
		kfree(name);
	}
J
Jeff Dike 已提交
151
	if (n < 0)
L
Linus Torvalds 已提交
152 153
		goto out_free;

J
Jeff Dike 已提交
154
	if (*name == '/')
J
Jeff Dike 已提交
155
		return name;
L
Linus Torvalds 已提交
156 157

	end = strrchr(link, '/');
J
Jeff Dike 已提交
158
	if (end == NULL)
J
Jeff Dike 已提交
159
		return name;
L
Linus Torvalds 已提交
160 161 162 163 164

	*(end + 1) = '\0';
	len = strlen(link) + strlen(name) + 1;

	resolved = kmalloc(len, GFP_KERNEL);
J
Jeff Dike 已提交
165
	if (resolved == NULL) {
L
Linus Torvalds 已提交
166 167 168 169 170 171 172
		n = -ENOMEM;
		goto out_free;
	}

	sprintf(resolved, "%s%s", link, name);
	kfree(name);
	kfree(link);
J
Jeff Dike 已提交
173
	return resolved;
L
Linus Torvalds 已提交
174 175 176 177

 out_free:
	kfree(name);
 out:
J
Jeff Dike 已提交
178
	return ERR_PTR(n);
L
Linus Torvalds 已提交
179 180
}

181 182
static struct inode *hostfs_iget(struct super_block *sb)
{
A
Al Viro 已提交
183
	struct inode *inode = new_inode(sb);
184 185 186 187 188
	if (!inode)
		return ERR_PTR(-ENOMEM);
	return inode;
}

189
int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
L
Linus Torvalds 已提交
190
{
J
Jeff Dike 已提交
191 192
	/*
	 * do_statfs uses struct statfs64 internally, but the linux kernel
L
Linus Torvalds 已提交
193 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;

203
	err = do_statfs(dentry->d_sb->s_fs_info,
L
Linus Torvalds 已提交
204 205
			&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
			&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
206
			&sf->f_namelen);
J
Jeff Dike 已提交
207
	if (err)
J
Jeff Dike 已提交
208
		return err;
L
Linus Torvalds 已提交
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;
J
Jeff Dike 已提交
215
	return 0;
L
Linus Torvalds 已提交
216 217 218 219 220 221
}

static struct inode *hostfs_alloc_inode(struct super_block *sb)
{
	struct hostfs_inode_info *hi;

222
	hi = kmalloc(sizeof(*hi), GFP_KERNEL);
J
Jeff Dike 已提交
223
	if (hi == NULL)
J
Jeff Dike 已提交
224
		return NULL;
225
	hi->fd = -1;
226
	hi->mode = 0;
L
Linus Torvalds 已提交
227
	inode_init_once(&hi->vfs_inode);
J
Jeff Dike 已提交
228
	return &hi->vfs_inode;
L
Linus Torvalds 已提交
229 230
}

231
static void hostfs_evict_inode(struct inode *inode)
L
Linus Torvalds 已提交
232
{
233
	truncate_inode_pages(&inode->i_data, 0);
234
	clear_inode(inode);
J
Jeff Dike 已提交
235
	if (HOSTFS_I(inode)->fd != -1) {
L
Linus Torvalds 已提交
236 237 238 239 240
		close_file(&HOSTFS_I(inode)->fd);
		HOSTFS_I(inode)->fd = -1;
	}
}

N
Nick Piggin 已提交
241
static void hostfs_i_callback(struct rcu_head *head)
L
Linus Torvalds 已提交
242
{
N
Nick Piggin 已提交
243
	struct inode *inode = container_of(head, struct inode, i_rcu);
L
Linus Torvalds 已提交
244 245
	kfree(HOSTFS_I(inode));
}
N
Nick Piggin 已提交
246 247 248 249 250

static void hostfs_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, hostfs_i_callback);
}
L
Linus Torvalds 已提交
251

252
static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
M
Miklos Szeredi 已提交
253
{
254
	const char *root_path = root->d_sb->s_fs_info;
M
Miklos Szeredi 已提交
255 256 257 258 259 260 261 262
	size_t offset = strlen(root_ino) + 1;

	if (strlen(root_path) > offset)
		seq_printf(seq, ",%s", root_path + offset);

	return 0;
}

263
static const struct super_operations hostfs_sbops = {
L
Linus Torvalds 已提交
264 265
	.alloc_inode	= hostfs_alloc_inode,
	.destroy_inode	= hostfs_destroy_inode,
266
	.evict_inode	= hostfs_evict_inode,
L
Linus Torvalds 已提交
267
	.statfs		= hostfs_statfs,
M
Miklos Szeredi 已提交
268
	.show_options	= hostfs_show_options,
L
Linus Torvalds 已提交
269 270
};

A
Al Viro 已提交
271
int hostfs_readdir(struct file *file, struct dir_context *ctx)
L
Linus Torvalds 已提交
272 273 274 275 276
{
	void *dir;
	char *name;
	unsigned long long next, ino;
	int error, len;
277
	unsigned int type;
L
Linus Torvalds 已提交
278

A
Al Viro 已提交
279
	name = dentry_name(file->f_path.dentry);
J
Jeff Dike 已提交
280
	if (name == NULL)
J
Jeff Dike 已提交
281
		return -ENOMEM;
L
Linus Torvalds 已提交
282
	dir = open_dir(name, &error);
283
	__putname(name);
J
Jeff Dike 已提交
284
	if (dir == NULL)
J
Jeff Dike 已提交
285
		return -error;
A
Al Viro 已提交
286
	next = ctx->pos;
287
	while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
A
Al Viro 已提交
288 289 290
		if (!dir_emit(ctx, name, len, ino, type))
			break;
		ctx->pos = next;
L
Linus Torvalds 已提交
291 292
	}
	close_dir(dir);
J
Jeff Dike 已提交
293
	return 0;
L
Linus Torvalds 已提交
294 295 296 297
}

int hostfs_file_open(struct inode *ino, struct file *file)
{
298
	static DEFINE_MUTEX(open_mutex);
L
Linus Torvalds 已提交
299
	char *name;
300
	fmode_t mode = 0;
301
	int err;
302
	int r = 0, w = 0, fd;
L
Linus Torvalds 已提交
303 304

	mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
J
Jeff Dike 已提交
305
	if ((mode & HOSTFS_I(ino)->mode) == mode)
J
Jeff Dike 已提交
306
		return 0;
L
Linus Torvalds 已提交
307

308
	mode |= HOSTFS_I(ino)->mode;
L
Linus Torvalds 已提交
309

310 311
retry:
	if (mode & FMODE_READ)
L
Linus Torvalds 已提交
312
		r = 1;
313
	if (mode & FMODE_WRITE)
L
Linus Torvalds 已提交
314
		w = 1;
J
Jeff Dike 已提交
315
	if (w)
L
Linus Torvalds 已提交
316 317
		r = 1;

A
Al Viro 已提交
318
	name = dentry_name(file->f_path.dentry);
J
Jeff Dike 已提交
319
	if (name == NULL)
J
Jeff Dike 已提交
320
		return -ENOMEM;
L
Linus Torvalds 已提交
321 322

	fd = open_file(name, r, w, append);
323
	__putname(name);
J
Jeff Dike 已提交
324
	if (fd < 0)
J
Jeff Dike 已提交
325
		return fd;
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350

	mutex_lock(&open_mutex);
	/* somebody else had handled it first? */
	if ((mode & HOSTFS_I(ino)->mode) == mode) {
		mutex_unlock(&open_mutex);
		return 0;
	}
	if ((mode | HOSTFS_I(ino)->mode) != mode) {
		mode |= HOSTFS_I(ino)->mode;
		mutex_unlock(&open_mutex);
		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) {
			mutex_unlock(&open_mutex);
			return err;
		}
	}
	HOSTFS_I(ino)->mode = mode;
	mutex_unlock(&open_mutex);
L
Linus Torvalds 已提交
351

J
Jeff Dike 已提交
352
	return 0;
L
Linus Torvalds 已提交
353 354
}

R
Richard Weinberger 已提交
355 356 357 358 359 360 361
static int hostfs_file_release(struct inode *inode, struct file *file)
{
	filemap_write_and_wait(inode->i_mapping);

	return 0;
}

362
int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
L
Linus Torvalds 已提交
363
{
364 365 366 367 368 369 370 371 372 373 374 375
	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;
L
Linus Torvalds 已提交
376 377
}

378
static const struct file_operations hostfs_file_fops = {
L
Linus Torvalds 已提交
379
	.llseek		= generic_file_llseek,
380
	.read		= do_sync_read,
381
	.splice_read	= generic_file_splice_read,
L
Linus Torvalds 已提交
382 383
	.aio_read	= generic_file_aio_read,
	.aio_write	= generic_file_aio_write,
384
	.write		= do_sync_write,
L
Linus Torvalds 已提交
385 386
	.mmap		= generic_file_mmap,
	.open		= hostfs_file_open,
R
Richard Weinberger 已提交
387
	.release	= hostfs_file_release,
L
Linus Torvalds 已提交
388 389 390
	.fsync		= hostfs_fsync,
};

391
static const struct file_operations hostfs_dir_fops = {
L
Linus Torvalds 已提交
392
	.llseek		= generic_file_llseek,
A
Al Viro 已提交
393
	.iterate	= hostfs_readdir,
L
Linus Torvalds 已提交
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
	.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);
J
Jeff Dike 已提交
414
	if (err != count) {
L
Linus Torvalds 已提交
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
		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);
J
Jeff Dike 已提交
443 444
	if (err < 0)
		goto out;
L
Linus Torvalds 已提交
445 446 447 448 449 450 451 452 453 454

	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);
J
Jeff Dike 已提交
455
	return err;
L
Linus Torvalds 已提交
456 457
}

N
Nick Piggin 已提交
458 459 460
int hostfs_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
L
Linus Torvalds 已提交
461
{
N
Nick Piggin 已提交
462
	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
L
Linus Torvalds 已提交
463

464
	*pagep = grab_cache_page_write_begin(mapping, index, flags);
N
Nick Piggin 已提交
465 466 467
	if (!*pagep)
		return -ENOMEM;
	return 0;
L
Linus Torvalds 已提交
468 469
}

N
Nick Piggin 已提交
470 471 472
int hostfs_write_end(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned copied,
			struct page *page, void *fsdata)
L
Linus Torvalds 已提交
473 474
{
	struct inode *inode = mapping->host;
N
Nick Piggin 已提交
475 476 477
	void *buffer;
	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
	int err;
L
Linus Torvalds 已提交
478 479

	buffer = kmap(page);
N
Nick Piggin 已提交
480 481
	err = write_file(FILE_HOSTFS_I(file)->fd, &pos, buffer + from, copied);
	kunmap(page);
482

N
Nick Piggin 已提交
483 484
	if (!PageUptodate(page) && err == PAGE_CACHE_SIZE)
		SetPageUptodate(page);
485

J
Jeff Dike 已提交
486 487
	/*
	 * If err > 0, write_file has added err to pos, so we are comparing
N
Nick Piggin 已提交
488 489 490 491 492 493
	 * 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);
L
Linus Torvalds 已提交
494

J
Jeff Dike 已提交
495
	return err;
L
Linus Torvalds 已提交
496 497
}

498
static const struct address_space_operations hostfs_aops = {
L
Linus Torvalds 已提交
499 500
	.writepage 	= hostfs_writepage,
	.readpage	= hostfs_readpage,
501
	.set_page_dirty = __set_page_dirty_nobuffers,
N
Nick Piggin 已提交
502 503
	.write_begin	= hostfs_write_begin,
	.write_end	= hostfs_write_end,
L
Linus Torvalds 已提交
504 505
};

506
static int read_name(struct inode *ino, char *name)
L
Linus Torvalds 已提交
507
{
508 509 510 511 512
	dev_t rdev;
	struct hostfs_stat st;
	int err = stat_file(name, &st, -1);
	if (err)
		return err;
L
Linus Torvalds 已提交
513

A
Al Viro 已提交
514
	/* Reencode maj and min with the kernel encoding.*/
515
	rdev = MKDEV(st.maj, st.min);
L
Linus Torvalds 已提交
516

517 518
	switch (st.mode & S_IFMT) {
	case S_IFLNK:
A
Al Viro 已提交
519
		ino->i_op = &hostfs_link_iops;
L
Linus Torvalds 已提交
520
		break;
521 522 523
	case S_IFDIR:
		ino->i_op = &hostfs_dir_iops;
		ino->i_fop = &hostfs_dir_fops;
L
Linus Torvalds 已提交
524
		break;
525 526 527 528 529 530
	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;
L
Linus Torvalds 已提交
531
		break;
532 533 534 535 536

	default:
		ino->i_op = &hostfs_iops;
		ino->i_fop = &hostfs_file_fops;
		ino->i_mapping->a_ops = &hostfs_aops;
L
Linus Torvalds 已提交
537
	}
538 539 540

	ino->i_ino = st.ino;
	ino->i_mode = st.mode;
M
Miklos Szeredi 已提交
541
	set_nlink(ino, st.nlink);
542 543
	i_uid_write(ino, st.uid);
	i_gid_write(ino, st.gid);
544 545 546 547 548 549
	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;
L
Linus Torvalds 已提交
550 551
}

A
Al Viro 已提交
552
int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
A
Al Viro 已提交
553
		  bool excl)
L
Linus Torvalds 已提交
554 555 556 557 558
{
	struct inode *inode;
	char *name;
	int error, fd;

559 560 561
	inode = hostfs_iget(dir->i_sb);
	if (IS_ERR(inode)) {
		error = PTR_ERR(inode);
J
Jeff Dike 已提交
562
		goto out;
563
	}
L
Linus Torvalds 已提交
564 565

	error = -ENOMEM;
A
Al Viro 已提交
566
	name = dentry_name(dentry);
J
Jeff Dike 已提交
567
	if (name == NULL)
L
Linus Torvalds 已提交
568 569 570 571 572 573
		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);
574
	if (fd < 0)
L
Linus Torvalds 已提交
575
		error = fd;
576
	else
A
Al Viro 已提交
577
		error = read_name(inode, name);
L
Linus Torvalds 已提交
578

579
	__putname(name);
J
Jeff Dike 已提交
580
	if (error)
L
Linus Torvalds 已提交
581 582 583 584 585
		goto out_put;

	HOSTFS_I(inode)->fd = fd;
	HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
	d_instantiate(dentry, inode);
J
Jeff Dike 已提交
586
	return 0;
L
Linus Torvalds 已提交
587 588 589 590

 out_put:
	iput(inode);
 out:
J
Jeff Dike 已提交
591
	return error;
L
Linus Torvalds 已提交
592 593 594
}

struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
A
Al Viro 已提交
595
			     unsigned int flags)
L
Linus Torvalds 已提交
596 597 598 599 600
{
	struct inode *inode;
	char *name;
	int err;

601 602 603
	inode = hostfs_iget(ino->i_sb);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
L
Linus Torvalds 已提交
604
		goto out;
605
	}
L
Linus Torvalds 已提交
606 607

	err = -ENOMEM;
A
Al Viro 已提交
608
	name = dentry_name(dentry);
J
Jeff Dike 已提交
609
	if (name == NULL)
L
Linus Torvalds 已提交
610 611 612
		goto out_put;

	err = read_name(inode, name);
A
Al Viro 已提交
613

614
	__putname(name);
J
Jeff Dike 已提交
615
	if (err == -ENOENT) {
L
Linus Torvalds 已提交
616 617 618
		iput(inode);
		inode = NULL;
	}
J
Jeff Dike 已提交
619
	else if (err)
L
Linus Torvalds 已提交
620 621 622
		goto out_put;

	d_add(dentry, inode);
J
Jeff Dike 已提交
623
	return NULL;
L
Linus Torvalds 已提交
624 625 626 627

 out_put:
	iput(inode);
 out:
J
Jeff Dike 已提交
628
	return ERR_PTR(err);
L
Linus Torvalds 已提交
629 630 631 632
}

int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
{
J
Jeff Dike 已提交
633 634
	char *from_name, *to_name;
	int err;
L
Linus Torvalds 已提交
635

A
Al Viro 已提交
636
	if ((from_name = dentry_name(from)) == NULL)
J
Jeff Dike 已提交
637
		return -ENOMEM;
A
Al Viro 已提交
638
	to_name = dentry_name(to);
J
Jeff Dike 已提交
639
	if (to_name == NULL) {
640
		__putname(from_name);
J
Jeff Dike 已提交
641
		return -ENOMEM;
L
Linus Torvalds 已提交
642
	}
J
Jeff Dike 已提交
643
	err = link_file(to_name, from_name);
644 645
	__putname(from_name);
	__putname(to_name);
J
Jeff Dike 已提交
646
	return err;
L
Linus Torvalds 已提交
647 648 649 650 651 652 653
}

int hostfs_unlink(struct inode *ino, struct dentry *dentry)
{
	char *file;
	int err;

J
Jeff Dike 已提交
654
	if (append)
J
Jeff Dike 已提交
655
		return -EPERM;
L
Linus Torvalds 已提交
656

A
Al Viro 已提交
657 658 659
	if ((file = dentry_name(dentry)) == NULL)
		return -ENOMEM;

L
Linus Torvalds 已提交
660
	err = unlink_file(file);
661
	__putname(file);
J
Jeff Dike 已提交
662
	return err;
L
Linus Torvalds 已提交
663 664 665 666 667 668 669
}

int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
{
	char *file;
	int err;

A
Al Viro 已提交
670
	if ((file = dentry_name(dentry)) == NULL)
J
Jeff Dike 已提交
671
		return -ENOMEM;
L
Linus Torvalds 已提交
672
	err = make_symlink(file, to);
673
	__putname(file);
J
Jeff Dike 已提交
674
	return err;
L
Linus Torvalds 已提交
675 676
}

677
int hostfs_mkdir(struct inode *ino, struct dentry *dentry, umode_t mode)
L
Linus Torvalds 已提交
678 679 680 681
{
	char *file;
	int err;

A
Al Viro 已提交
682
	if ((file = dentry_name(dentry)) == NULL)
J
Jeff Dike 已提交
683
		return -ENOMEM;
L
Linus Torvalds 已提交
684
	err = do_mkdir(file, mode);
685
	__putname(file);
J
Jeff Dike 已提交
686
	return err;
L
Linus Torvalds 已提交
687 688 689 690 691 692 693
}

int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
{
	char *file;
	int err;

A
Al Viro 已提交
694
	if ((file = dentry_name(dentry)) == NULL)
J
Jeff Dike 已提交
695
		return -ENOMEM;
L
Linus Torvalds 已提交
696
	err = do_rmdir(file);
697
	__putname(file);
J
Jeff Dike 已提交
698
	return err;
L
Linus Torvalds 已提交
699 700
}

A
Al Viro 已提交
701
static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
L
Linus Torvalds 已提交
702 703 704
{
	struct inode *inode;
	char *name;
705
	int err;
L
Linus Torvalds 已提交
706

707 708 709
	inode = hostfs_iget(dir->i_sb);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
L
Linus Torvalds 已提交
710
		goto out;
711
	}
L
Linus Torvalds 已提交
712 713

	err = -ENOMEM;
A
Al Viro 已提交
714
	name = dentry_name(dentry);
J
Jeff Dike 已提交
715
	if (name == NULL)
L
Linus Torvalds 已提交
716 717 718
		goto out_put;

	init_special_inode(inode, mode, dev);
J
Johannes Stezenbach 已提交
719
	err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
720
	if (!err)
L
Linus Torvalds 已提交
721 722 723
		goto out_free;

	err = read_name(inode, name);
724
	__putname(name);
A
Al Viro 已提交
725 726
	if (err)
		goto out_put;
J
Jeff Dike 已提交
727
	if (err)
L
Linus Torvalds 已提交
728 729 730
		goto out_put;

	d_instantiate(dentry, inode);
J
Jeff Dike 已提交
731
	return 0;
L
Linus Torvalds 已提交
732 733

 out_free:
734
	__putname(name);
L
Linus Torvalds 已提交
735 736 737
 out_put:
	iput(inode);
 out:
J
Jeff Dike 已提交
738
	return err;
L
Linus Torvalds 已提交
739 740 741 742 743 744 745 746
}

int hostfs_rename(struct inode *from_ino, struct dentry *from,
		  struct inode *to_ino, struct dentry *to)
{
	char *from_name, *to_name;
	int err;

A
Al Viro 已提交
747
	if ((from_name = dentry_name(from)) == NULL)
J
Jeff Dike 已提交
748
		return -ENOMEM;
A
Al Viro 已提交
749
	if ((to_name = dentry_name(to)) == NULL) {
750
		__putname(from_name);
J
Jeff Dike 已提交
751
		return -ENOMEM;
L
Linus Torvalds 已提交
752 753
	}
	err = rename_file(from_name, to_name);
754 755
	__putname(from_name);
	__putname(to_name);
J
Jeff Dike 已提交
756
	return err;
L
Linus Torvalds 已提交
757 758
}

759
int hostfs_permission(struct inode *ino, int desired)
L
Linus Torvalds 已提交
760 761 762 763
{
	char *name;
	int r = 0, w = 0, x = 0, err;

764
	if (desired & MAY_NOT_BLOCK)
765 766
		return -ECHILD;

L
Linus Torvalds 已提交
767 768 769
	if (desired & MAY_READ) r = 1;
	if (desired & MAY_WRITE) w = 1;
	if (desired & MAY_EXEC) x = 1;
A
Al Viro 已提交
770
	name = inode_name(ino);
J
Jeff Dike 已提交
771 772
	if (name == NULL)
		return -ENOMEM;
L
Linus Torvalds 已提交
773 774

	if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
J
Jeff Dike 已提交
775
	    S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
L
Linus Torvalds 已提交
776 777 778
		err = 0;
	else
		err = access_file(name, r, w, x);
779
	__putname(name);
J
Jeff Dike 已提交
780
	if (!err)
781
		err = generic_permission(ino, desired);
L
Linus Torvalds 已提交
782 783 784 785 786
	return err;
}

int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
{
C
Christoph Hellwig 已提交
787
	struct inode *inode = dentry->d_inode;
L
Linus Torvalds 已提交
788 789 790 791
	struct hostfs_iattr attrs;
	char *name;
	int err;

C
Christoph Hellwig 已提交
792
	int fd = HOSTFS_I(inode)->fd;
793

C
Christoph Hellwig 已提交
794
	err = inode_change_ok(inode, attr);
L
Linus Torvalds 已提交
795 796 797
	if (err)
		return err;

J
Jeff Dike 已提交
798
	if (append)
L
Linus Torvalds 已提交
799 800 801
		attr->ia_valid &= ~ATTR_SIZE;

	attrs.ia_valid = 0;
J
Jeff Dike 已提交
802
	if (attr->ia_valid & ATTR_MODE) {
L
Linus Torvalds 已提交
803 804 805
		attrs.ia_valid |= HOSTFS_ATTR_MODE;
		attrs.ia_mode = attr->ia_mode;
	}
J
Jeff Dike 已提交
806
	if (attr->ia_valid & ATTR_UID) {
L
Linus Torvalds 已提交
807
		attrs.ia_valid |= HOSTFS_ATTR_UID;
808
		attrs.ia_uid = from_kuid(&init_user_ns, attr->ia_uid);
L
Linus Torvalds 已提交
809
	}
J
Jeff Dike 已提交
810
	if (attr->ia_valid & ATTR_GID) {
L
Linus Torvalds 已提交
811
		attrs.ia_valid |= HOSTFS_ATTR_GID;
812
		attrs.ia_gid = from_kgid(&init_user_ns, attr->ia_gid);
L
Linus Torvalds 已提交
813
	}
J
Jeff Dike 已提交
814
	if (attr->ia_valid & ATTR_SIZE) {
L
Linus Torvalds 已提交
815 816 817
		attrs.ia_valid |= HOSTFS_ATTR_SIZE;
		attrs.ia_size = attr->ia_size;
	}
J
Jeff Dike 已提交
818
	if (attr->ia_valid & ATTR_ATIME) {
L
Linus Torvalds 已提交
819 820 821
		attrs.ia_valid |= HOSTFS_ATTR_ATIME;
		attrs.ia_atime = attr->ia_atime;
	}
J
Jeff Dike 已提交
822
	if (attr->ia_valid & ATTR_MTIME) {
L
Linus Torvalds 已提交
823 824 825
		attrs.ia_valid |= HOSTFS_ATTR_MTIME;
		attrs.ia_mtime = attr->ia_mtime;
	}
J
Jeff Dike 已提交
826
	if (attr->ia_valid & ATTR_CTIME) {
L
Linus Torvalds 已提交
827 828 829
		attrs.ia_valid |= HOSTFS_ATTR_CTIME;
		attrs.ia_ctime = attr->ia_ctime;
	}
J
Jeff Dike 已提交
830
	if (attr->ia_valid & ATTR_ATIME_SET) {
L
Linus Torvalds 已提交
831 832
		attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
	}
J
Jeff Dike 已提交
833
	if (attr->ia_valid & ATTR_MTIME_SET) {
L
Linus Torvalds 已提交
834 835
		attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
	}
A
Al Viro 已提交
836
	name = dentry_name(dentry);
J
Jeff Dike 已提交
837
	if (name == NULL)
J
Jeff Dike 已提交
838
		return -ENOMEM;
839
	err = set_attr(name, &attrs, fd);
840
	__putname(name);
J
Jeff Dike 已提交
841
	if (err)
J
Jeff Dike 已提交
842
		return err;
L
Linus Torvalds 已提交
843

C
Christoph Hellwig 已提交
844
	if ((attr->ia_valid & ATTR_SIZE) &&
845
	    attr->ia_size != i_size_read(inode))
M
Marco Stornelli 已提交
846
		truncate_setsize(inode, attr->ia_size);
C
Christoph Hellwig 已提交
847 848 849 850

	setattr_copy(inode, attr);
	mark_inode_dirty(inode);
	return 0;
L
Linus Torvalds 已提交
851 852
}

853
static const struct inode_operations hostfs_iops = {
L
Linus Torvalds 已提交
854 855 856 857
	.permission	= hostfs_permission,
	.setattr	= hostfs_setattr,
};

858
static const struct inode_operations hostfs_dir_iops = {
L
Linus Torvalds 已提交
859 860 861 862 863 864 865 866 867 868 869 870 871
	.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,
	.permission	= hostfs_permission,
	.setattr	= hostfs_setattr,
};

A
Al Viro 已提交
872 873 874 875 876 877 878
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) {
A
Al Viro 已提交
879
			err = hostfs_do_readlink(path, link, PATH_MAX);
A
Al Viro 已提交
880 881
			if (err == PATH_MAX)
				err = -E2BIG;
882
			__putname(path);
A
Al Viro 已提交
883 884 885 886 887 888 889
		}
		if (err < 0) {
			__putname(link);
			link = ERR_PTR(err);
		}
	} else {
		link = ERR_PTR(-ENOMEM);
L
Linus Torvalds 已提交
890
	}
A
Al Viro 已提交
891 892 893 894 895 896 897 898 899 900

	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);
L
Linus Torvalds 已提交
901 902
}

A
Al Viro 已提交
903 904 905 906
static const struct inode_operations hostfs_link_iops = {
	.readlink	= generic_readlink,
	.follow_link	= hostfs_follow_link,
	.put_link	= hostfs_put_link,
L
Linus Torvalds 已提交
907 908 909 910 911
};

static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
{
	struct inode *root_inode;
912
	char *host_root_path, *req_root = d;
L
Linus Torvalds 已提交
913 914 915 916 917 918
	int err;

	sb->s_blocksize = 1024;
	sb->s_blocksize_bits = 10;
	sb->s_magic = HOSTFS_SUPER_MAGIC;
	sb->s_op = &hostfs_sbops;
919
	sb->s_d_op = &simple_dentry_operations;
920
	sb->s_maxbytes = MAX_LFS_FILESIZE;
L
Linus Torvalds 已提交
921

922
	/* NULL is printed as <NULL> by sprintf: avoid that. */
923 924
	if (req_root == NULL)
		req_root = "";
L
Linus Torvalds 已提交
925 926

	err = -ENOMEM;
927 928
	sb->s_fs_info = host_root_path =
		kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL);
J
Jeff Dike 已提交
929
	if (host_root_path == NULL)
L
Linus Torvalds 已提交
930 931
		goto out;

932
	sprintf(host_root_path, "%s/%s", root_ino, req_root);
L
Linus Torvalds 已提交
933

A
Al Viro 已提交
934 935
	root_inode = new_inode(sb);
	if (!root_inode)
936
		goto out;
L
Linus Torvalds 已提交
937

938 939 940
	err = read_name(root_inode, host_root_path);
	if (err)
		goto out_put;
A
Al Viro 已提交
941

942
	if (S_ISLNK(root_inode->i_mode)) {
A
Al Viro 已提交
943 944 945 946 947 948
		char *name = follow_link(host_root_path);
		if (IS_ERR(name))
			err = PTR_ERR(name);
		else
			err = read_name(root_inode, name);
		kfree(name);
949 950
		if (err)
			goto out_put;
A
Al Viro 已提交
951
	}
L
Linus Torvalds 已提交
952 953

	err = -ENOMEM;
954
	sb->s_root = d_make_root(root_inode);
J
Jeff Dike 已提交
955
	if (sb->s_root == NULL)
956
		goto out;
L
Linus Torvalds 已提交
957

J
Jeff Dike 已提交
958
	return 0;
L
Linus Torvalds 已提交
959

J
Jeff Dike 已提交
960 961 962 963
out_put:
	iput(root_inode);
out:
	return err;
L
Linus Torvalds 已提交
964 965
}

A
Al Viro 已提交
966
static struct dentry *hostfs_read_sb(struct file_system_type *type,
967
			  int flags, const char *dev_name,
A
Al Viro 已提交
968
			  void *data)
L
Linus Torvalds 已提交
969
{
A
Al Viro 已提交
970
	return mount_nodev(type, flags, data, hostfs_fill_sb_common);
L
Linus Torvalds 已提交
971 972
}

973 974 975 976 977 978
static void hostfs_kill_sb(struct super_block *s)
{
	kill_anon_super(s);
	kfree(s->s_fs_info);
}

L
Linus Torvalds 已提交
979 980 981
static struct file_system_type hostfs_type = {
	.owner 		= THIS_MODULE,
	.name 		= "hostfs",
A
Al Viro 已提交
982
	.mount	 	= hostfs_read_sb,
983
	.kill_sb	= hostfs_kill_sb,
L
Linus Torvalds 已提交
984 985
	.fs_flags 	= 0,
};
986
MODULE_ALIAS_FS("hostfs");
L
Linus Torvalds 已提交
987 988 989

static int __init init_hostfs(void)
{
J
Jeff Dike 已提交
990
	return register_filesystem(&hostfs_type);
L
Linus Torvalds 已提交
991 992 993 994 995 996 997 998 999 1000
}

static void __exit exit_hostfs(void)
{
	unregister_filesystem(&hostfs_type);
}

module_init(init_hostfs)
module_exit(exit_hostfs)
MODULE_LICENSE("GPL");