vfs_super.c 4.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 *  linux/fs/9p/vfs_super.c
 *
 * This file contians superblock ops for 9P2000. It is intended that
 * you mount this file system on directories.
 *
 *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
 *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
 *
 *  This program is free software; you can redistribute it and/or modify
11 12
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to:
 *  Free Software Foundation
 *  51 Franklin Street, Fifth Floor
 *  Boston, MA  02111-1301  USA
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/inet.h>
#include <linux/pagemap.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/idr.h>
A
Alexey Dobriyan 已提交
39
#include <linux/sched.h>
40 41
#include <net/9p/9p.h>
#include <net/9p/client.h>
42 43 44 45 46

#include "v9fs.h"
#include "v9fs_vfs.h"
#include "fid.h"

47
static const struct super_operations v9fs_super_ops;
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

/**
 * v9fs_set_super - set the superblock
 * @s: super block
 * @data: file system specific data
 *
 */

static int v9fs_set_super(struct super_block *s, void *data)
{
	s->s_fs_info = data;
	return set_anon_super(s, data);
}

/**
 * v9fs_fill_super - populate superblock with info
 * @sb: superblock
 * @v9ses: session information
E
Eric Van Hensbergen 已提交
66
 * @flags: flags propagated from v9fs_get_sb()
67 68 69 70 71
 *
 */

static void
v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
72
		int flags, void *data)
73 74 75 76 77 78 79 80
{
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
	sb->s_blocksize = 1 << sb->s_blocksize_bits;
	sb->s_magic = V9FS_MAGIC;
	sb->s_op = &v9fs_super_ops;

	sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
81
	    MS_NOATIME;
82 83

	save_mount_options(sb, data);
84 85 86 87 88 89 90 91
}

/**
 * v9fs_get_sb - mount a superblock
 * @fs_type: file system type
 * @flags: mount flags
 * @dev_name: device name that was mounted
 * @data: mount options
92
 * @mnt: mountpoint record to be instantiated
93 94 95
 *
 */

96 97 98
static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
		       const char *dev_name, void *data,
		       struct vfsmount *mnt)
99 100 101 102 103
{
	struct super_block *sb = NULL;
	struct inode *inode = NULL;
	struct dentry *root = NULL;
	struct v9fs_session_info *v9ses = NULL;
104
	struct p9_wstat *st = NULL;
105
	int mode = S_IRWXUGO | S_ISVTX;
106
	struct p9_fid *fid;
107 108
	int retval = 0;

109
	P9_DPRINTK(P9_DEBUG_VFS, " \n");
110

111
	v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
112
	if (!v9ses)
113
		return -ENOMEM;
114

115 116 117
	fid = v9fs_session_init(v9ses, dev_name, data);
	if (IS_ERR(fid)) {
		retval = PTR_ERR(fid);
118
		goto close_session;
119 120 121 122 123
	}

	st = p9_client_stat(fid);
	if (IS_ERR(st)) {
		retval = PTR_ERR(st);
124
		goto clunk_fid;
125 126 127
	}

	sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
128 129
	if (IS_ERR(sb)) {
		retval = PTR_ERR(sb);
130
		goto free_stat;
131
	}
132
	v9fs_fill_super(sb, v9ses, flags, data);
133 134 135 136

	inode = v9fs_get_inode(sb, S_IFDIR | mode);
	if (IS_ERR(inode)) {
		retval = PTR_ERR(inode);
137
		goto release_sb;
138 139 140 141
	}

	root = d_alloc_root(inode);
	if (!root) {
142
		iput(inode);
143
		retval = -ENOMEM;
144
		goto release_sb;
145 146 147
	}

	sb->s_root = root;
148
	root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
149

150
	v9fs_stat2inode(st, root->d_inode, sb);
151

152
	v9fs_fid_add(root, fid);
153
	p9stat_free(st);
154
	kfree(st);
155

156 157 158
P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
	simple_set_mnt(mnt, sb);
	return 0;
159

160
free_stat:
161
	p9stat_free(st);
162 163 164 165 166 167 168 169
	kfree(st);

clunk_fid:
	p9_client_clunk(fid);

close_session:
	v9fs_session_close(v9ses);
	kfree(v9ses);
170
	return retval;
171

172 173 174 175
release_sb:
	p9stat_free(st);
	kfree(st);
	deactivate_locked_super(sb);
176
	return retval;
177 178 179 180 181 182 183 184 185 186 187 188
}

/**
 * v9fs_kill_super - Kill Superblock
 * @s: superblock
 *
 */

static void v9fs_kill_super(struct super_block *s)
{
	struct v9fs_session_info *v9ses = s->s_fs_info;

189
	P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s);
190

A
Al Viro 已提交
191 192
	if (s->s_root)
		v9fs_dentry_release(s->s_root);	/* clunk root */
193 194 195 196 197

	kill_anon_super(s);

	v9fs_session_close(v9ses);
	kfree(v9ses);
198
	s->s_fs_info = NULL;
199
	P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n");
200 201
}

202
static void
203
v9fs_umount_begin(struct super_block *sb)
204
{
205
	struct v9fs_session_info *v9ses;
206

207
	v9ses = sb->s_fs_info;
208
	v9fs_session_cancel(v9ses);
209 210
}

211
static const struct super_operations v9fs_super_ops = {
212 213 214 215
#ifdef CONFIG_9P_FSCACHE
	.alloc_inode = v9fs_alloc_inode,
	.destroy_inode = v9fs_destroy_inode,
#endif
216 217
	.statfs = simple_statfs,
	.clear_inode = v9fs_clear_inode,
218
	.show_options = generic_show_options,
219
	.umount_begin = v9fs_umount_begin,
220 221 222
};

struct file_system_type v9fs_fs_type = {
223
	.name = "9p",
224 225 226 227
	.get_sb = v9fs_get_sb,
	.kill_sb = v9fs_kill_super,
	.owner = THIS_MODULE,
};