19e82cf6aSEric Van Hensbergen /* 29e82cf6aSEric Van Hensbergen * linux/fs/9p/vfs_super.c 39e82cf6aSEric Van Hensbergen * 49e82cf6aSEric Van Hensbergen * This file contians superblock ops for 9P2000. It is intended that 59e82cf6aSEric Van Hensbergen * you mount this file system on directories. 69e82cf6aSEric Van Hensbergen * 79e82cf6aSEric Van Hensbergen * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 89e82cf6aSEric Van Hensbergen * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 99e82cf6aSEric Van Hensbergen * 109e82cf6aSEric Van Hensbergen * This program is free software; you can redistribute it and/or modify 1142e8c509SEric Van Hensbergen * it under the terms of the GNU General Public License version 2 1242e8c509SEric Van Hensbergen * as published by the Free Software Foundation. 139e82cf6aSEric Van Hensbergen * 149e82cf6aSEric Van Hensbergen * This program is distributed in the hope that it will be useful, 159e82cf6aSEric Van Hensbergen * but WITHOUT ANY WARRANTY; without even the implied warranty of 169e82cf6aSEric Van Hensbergen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 179e82cf6aSEric Van Hensbergen * GNU General Public License for more details. 189e82cf6aSEric Van Hensbergen * 199e82cf6aSEric Van Hensbergen * You should have received a copy of the GNU General Public License 209e82cf6aSEric Van Hensbergen * along with this program; if not, write to: 219e82cf6aSEric Van Hensbergen * Free Software Foundation 229e82cf6aSEric Van Hensbergen * 51 Franklin Street, Fifth Floor 239e82cf6aSEric Van Hensbergen * Boston, MA 02111-1301 USA 249e82cf6aSEric Van Hensbergen * 259e82cf6aSEric Van Hensbergen */ 269e82cf6aSEric Van Hensbergen 279e82cf6aSEric Van Hensbergen #include <linux/kernel.h> 289e82cf6aSEric Van Hensbergen #include <linux/config.h> 299e82cf6aSEric Van Hensbergen #include <linux/module.h> 309e82cf6aSEric Van Hensbergen #include <linux/errno.h> 319e82cf6aSEric Van Hensbergen #include <linux/fs.h> 329e82cf6aSEric Van Hensbergen #include <linux/file.h> 339e82cf6aSEric Van Hensbergen #include <linux/stat.h> 349e82cf6aSEric Van Hensbergen #include <linux/string.h> 359e82cf6aSEric Van Hensbergen #include <linux/smp_lock.h> 369e82cf6aSEric Van Hensbergen #include <linux/inet.h> 379e82cf6aSEric Van Hensbergen #include <linux/pagemap.h> 389e82cf6aSEric Van Hensbergen #include <linux/seq_file.h> 399e82cf6aSEric Van Hensbergen #include <linux/mount.h> 409e82cf6aSEric Van Hensbergen #include <linux/idr.h> 419e82cf6aSEric Van Hensbergen 429e82cf6aSEric Van Hensbergen #include "debug.h" 439e82cf6aSEric Van Hensbergen #include "v9fs.h" 449e82cf6aSEric Van Hensbergen #include "9p.h" 459e82cf6aSEric Van Hensbergen #include "v9fs_vfs.h" 469e82cf6aSEric Van Hensbergen #include "fid.h" 479e82cf6aSEric Van Hensbergen 489e82cf6aSEric Van Hensbergen static void v9fs_clear_inode(struct inode *); 499e82cf6aSEric Van Hensbergen static struct super_operations v9fs_super_ops; 509e82cf6aSEric Van Hensbergen 519e82cf6aSEric Van Hensbergen /** 529e82cf6aSEric Van Hensbergen * v9fs_clear_inode - release an inode 539e82cf6aSEric Van Hensbergen * @inode: inode to release 549e82cf6aSEric Van Hensbergen * 559e82cf6aSEric Van Hensbergen */ 569e82cf6aSEric Van Hensbergen 579e82cf6aSEric Van Hensbergen static void v9fs_clear_inode(struct inode *inode) 589e82cf6aSEric Van Hensbergen { 599e82cf6aSEric Van Hensbergen filemap_fdatawrite(inode->i_mapping); 609e82cf6aSEric Van Hensbergen } 619e82cf6aSEric Van Hensbergen 629e82cf6aSEric Van Hensbergen /** 639e82cf6aSEric Van Hensbergen * v9fs_set_super - set the superblock 649e82cf6aSEric Van Hensbergen * @s: super block 659e82cf6aSEric Van Hensbergen * @data: file system specific data 669e82cf6aSEric Van Hensbergen * 679e82cf6aSEric Van Hensbergen */ 689e82cf6aSEric Van Hensbergen 699e82cf6aSEric Van Hensbergen static int v9fs_set_super(struct super_block *s, void *data) 709e82cf6aSEric Van Hensbergen { 719e82cf6aSEric Van Hensbergen s->s_fs_info = data; 729e82cf6aSEric Van Hensbergen return set_anon_super(s, data); 739e82cf6aSEric Van Hensbergen } 749e82cf6aSEric Van Hensbergen 759e82cf6aSEric Van Hensbergen /** 769e82cf6aSEric Van Hensbergen * v9fs_fill_super - populate superblock with info 779e82cf6aSEric Van Hensbergen * @sb: superblock 789e82cf6aSEric Van Hensbergen * @v9ses: session information 799e82cf6aSEric Van Hensbergen * 809e82cf6aSEric Van Hensbergen */ 819e82cf6aSEric Van Hensbergen 829e82cf6aSEric Van Hensbergen static void 839e82cf6aSEric Van Hensbergen v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, 849e82cf6aSEric Van Hensbergen int flags) 859e82cf6aSEric Van Hensbergen { 869e82cf6aSEric Van Hensbergen sb->s_maxbytes = MAX_LFS_FILESIZE; 879e82cf6aSEric Van Hensbergen sb->s_blocksize_bits = fls(v9ses->maxdata - 1); 889e82cf6aSEric Van Hensbergen sb->s_blocksize = 1 << sb->s_blocksize_bits; 899e82cf6aSEric Van Hensbergen sb->s_magic = V9FS_MAGIC; 909e82cf6aSEric Van Hensbergen sb->s_op = &v9fs_super_ops; 919e82cf6aSEric Van Hensbergen 929e82cf6aSEric Van Hensbergen sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC | 930d456fa4SChristoph Hellwig MS_NOATIME; 949e82cf6aSEric Van Hensbergen } 959e82cf6aSEric Van Hensbergen 969e82cf6aSEric Van Hensbergen /** 979e82cf6aSEric Van Hensbergen * v9fs_get_sb - mount a superblock 989e82cf6aSEric Van Hensbergen * @fs_type: file system type 999e82cf6aSEric Van Hensbergen * @flags: mount flags 1009e82cf6aSEric Van Hensbergen * @dev_name: device name that was mounted 1019e82cf6aSEric Van Hensbergen * @data: mount options 102454e2398SDavid Howells * @mnt: mountpoint record to be instantiated 1039e82cf6aSEric Van Hensbergen * 1049e82cf6aSEric Van Hensbergen */ 1059e82cf6aSEric Van Hensbergen 106454e2398SDavid Howells static int v9fs_get_sb(struct file_system_type *fs_type, int flags, 107454e2398SDavid Howells const char *dev_name, void *data, 108454e2398SDavid Howells struct vfsmount *mnt) 1099e82cf6aSEric Van Hensbergen { 1109e82cf6aSEric Van Hensbergen struct super_block *sb = NULL; 1119e82cf6aSEric Van Hensbergen struct v9fs_fcall *fcall = NULL; 1129e82cf6aSEric Van Hensbergen struct inode *inode = NULL; 1139e82cf6aSEric Van Hensbergen struct dentry *root = NULL; 1149e82cf6aSEric Van Hensbergen struct v9fs_session_info *v9ses = NULL; 1159e82cf6aSEric Van Hensbergen struct v9fs_fid *root_fid = NULL; 1169e82cf6aSEric Van Hensbergen int mode = S_IRWXUGO | S_ISVTX; 1179e82cf6aSEric Van Hensbergen uid_t uid = current->fsuid; 1189e82cf6aSEric Van Hensbergen gid_t gid = current->fsgid; 1199e82cf6aSEric Van Hensbergen int stat_result = 0; 1209e82cf6aSEric Van Hensbergen int newfid = 0; 1219e82cf6aSEric Van Hensbergen int retval = 0; 1229e82cf6aSEric Van Hensbergen 1239e82cf6aSEric Van Hensbergen dprintk(DEBUG_VFS, " \n"); 1249e82cf6aSEric Van Hensbergen 1251dac06b2SLatchesar Ionkov v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); 1269e82cf6aSEric Van Hensbergen if (!v9ses) 127454e2398SDavid Howells return -ENOMEM; 1289e82cf6aSEric Van Hensbergen 1299e82cf6aSEric Van Hensbergen if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { 1309e82cf6aSEric Van Hensbergen dprintk(DEBUG_ERROR, "problem initiating session\n"); 131454e2398SDavid Howells retval = newfid; 13200fbc6dfSEric Van Hensbergen goto out_free_session; 1339e82cf6aSEric Van Hensbergen } 1349e82cf6aSEric Van Hensbergen 1359e82cf6aSEric Van Hensbergen sb = sget(fs_type, NULL, v9fs_set_super, v9ses); 136454e2398SDavid Howells if (IS_ERR(sb)) { 137454e2398SDavid Howells retval = PTR_ERR(sb); 13800fbc6dfSEric Van Hensbergen goto out_close_session; 139454e2398SDavid Howells } 1409e82cf6aSEric Van Hensbergen v9fs_fill_super(sb, v9ses, flags); 1419e82cf6aSEric Van Hensbergen 1429e82cf6aSEric Van Hensbergen inode = v9fs_get_inode(sb, S_IFDIR | mode); 1439e82cf6aSEric Van Hensbergen if (IS_ERR(inode)) { 1449e82cf6aSEric Van Hensbergen retval = PTR_ERR(inode); 1459e82cf6aSEric Van Hensbergen goto put_back_sb; 1469e82cf6aSEric Van Hensbergen } 1479e82cf6aSEric Van Hensbergen 1489e82cf6aSEric Van Hensbergen inode->i_uid = uid; 1499e82cf6aSEric Van Hensbergen inode->i_gid = gid; 1509e82cf6aSEric Van Hensbergen 1519e82cf6aSEric Van Hensbergen root = d_alloc_root(inode); 1529e82cf6aSEric Van Hensbergen if (!root) { 1539e82cf6aSEric Van Hensbergen retval = -ENOMEM; 154f71626a4SLatchesar Ionkov goto put_back_sb; 1559e82cf6aSEric Van Hensbergen } 1569e82cf6aSEric Van Hensbergen 1579e82cf6aSEric Van Hensbergen sb->s_root = root; 1589e82cf6aSEric Van Hensbergen 1599e82cf6aSEric Van Hensbergen stat_result = v9fs_t_stat(v9ses, newfid, &fcall); 1609e82cf6aSEric Van Hensbergen if (stat_result < 0) { 1619e82cf6aSEric Van Hensbergen dprintk(DEBUG_ERROR, "stat error\n"); 1623cf6429aSLatchesar Ionkov v9fs_t_clunk(v9ses, newfid); 1639e82cf6aSEric Van Hensbergen } else { 1640b8dd177SLatchesar Ionkov /* Setup the Root Inode */ 1656a3124a3SLatchesar Ionkov root_fid = v9fs_fid_create(v9ses, newfid); 1660b8dd177SLatchesar Ionkov if (root_fid == NULL) { 1670b8dd177SLatchesar Ionkov retval = -ENOMEM; 1680b8dd177SLatchesar Ionkov goto put_back_sb; 1690b8dd177SLatchesar Ionkov } 1700b8dd177SLatchesar Ionkov 1716a3124a3SLatchesar Ionkov retval = v9fs_fid_insert(root_fid, root); 17274b8054cSEric Van Hensbergen if (retval < 0) { 17374b8054cSEric Van Hensbergen kfree(fcall); 1746a3124a3SLatchesar Ionkov goto put_back_sb; 17574b8054cSEric Van Hensbergen } 1766a3124a3SLatchesar Ionkov 177531b1094SLatchesar Ionkov root_fid->qid = fcall->params.rstat.stat.qid; 1789e82cf6aSEric Van Hensbergen root->d_inode->i_ino = 179531b1094SLatchesar Ionkov v9fs_qid2ino(&fcall->params.rstat.stat.qid); 180531b1094SLatchesar Ionkov v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb); 1819e82cf6aSEric Van Hensbergen } 1829e82cf6aSEric Van Hensbergen 18374b8054cSEric Van Hensbergen kfree(fcall); 18474b8054cSEric Van Hensbergen 1859e82cf6aSEric Van Hensbergen if (stat_result < 0) { 1869e82cf6aSEric Van Hensbergen retval = stat_result; 187f71626a4SLatchesar Ionkov goto put_back_sb; 1889e82cf6aSEric Van Hensbergen } 1899e82cf6aSEric Van Hensbergen 190454e2398SDavid Howells return simple_set_mnt(mnt, sb); 1919e82cf6aSEric Van Hensbergen 19200fbc6dfSEric Van Hensbergen out_close_session: 19300fbc6dfSEric Van Hensbergen v9fs_session_close(v9ses); 19400fbc6dfSEric Van Hensbergen out_free_session: 19500fbc6dfSEric Van Hensbergen kfree(v9ses); 196454e2398SDavid Howells return retval; 19700fbc6dfSEric Van Hensbergen 1989e82cf6aSEric Van Hensbergen put_back_sb: 199f71626a4SLatchesar Ionkov /* deactivate_super calls v9fs_kill_super which will frees the rest */ 2009e82cf6aSEric Van Hensbergen up_write(&sb->s_umount); 2019e82cf6aSEric Van Hensbergen deactivate_super(sb); 202454e2398SDavid Howells return retval; 2039e82cf6aSEric Van Hensbergen } 2049e82cf6aSEric Van Hensbergen 2059e82cf6aSEric Van Hensbergen /** 2069e82cf6aSEric Van Hensbergen * v9fs_kill_super - Kill Superblock 2079e82cf6aSEric Van Hensbergen * @s: superblock 2089e82cf6aSEric Van Hensbergen * 2099e82cf6aSEric Van Hensbergen */ 2109e82cf6aSEric Van Hensbergen 2119e82cf6aSEric Van Hensbergen static void v9fs_kill_super(struct super_block *s) 2129e82cf6aSEric Van Hensbergen { 2139e82cf6aSEric Van Hensbergen struct v9fs_session_info *v9ses = s->s_fs_info; 2149e82cf6aSEric Van Hensbergen 2159e82cf6aSEric Van Hensbergen dprintk(DEBUG_VFS, " %p\n", s); 2169e82cf6aSEric Van Hensbergen 2179e82cf6aSEric Van Hensbergen v9fs_dentry_release(s->s_root); /* clunk root */ 2189e82cf6aSEric Van Hensbergen 2199e82cf6aSEric Van Hensbergen kill_anon_super(s); 2209e82cf6aSEric Van Hensbergen 2219e82cf6aSEric Van Hensbergen v9fs_session_close(v9ses); 2229e82cf6aSEric Van Hensbergen kfree(v9ses); 2239e82cf6aSEric Van Hensbergen dprintk(DEBUG_VFS, "exiting kill_super\n"); 2249e82cf6aSEric Van Hensbergen } 2259e82cf6aSEric Van Hensbergen 2269e82cf6aSEric Van Hensbergen /** 2279e82cf6aSEric Van Hensbergen * v9fs_show_options - Show mount options in /proc/mounts 2289e82cf6aSEric Van Hensbergen * @m: seq_file to write to 2299e82cf6aSEric Van Hensbergen * @mnt: mount descriptor 2309e82cf6aSEric Van Hensbergen * 2319e82cf6aSEric Van Hensbergen */ 2329e82cf6aSEric Van Hensbergen 2339e82cf6aSEric Van Hensbergen static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt) 2349e82cf6aSEric Van Hensbergen { 2359e82cf6aSEric Van Hensbergen struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info; 2369e82cf6aSEric Van Hensbergen 2379e82cf6aSEric Van Hensbergen if (v9ses->debug != 0) 2389e82cf6aSEric Van Hensbergen seq_printf(m, ",debug=%u", v9ses->debug); 2399e82cf6aSEric Van Hensbergen if (v9ses->port != V9FS_PORT) 2409e82cf6aSEric Van Hensbergen seq_printf(m, ",port=%u", v9ses->port); 2419e82cf6aSEric Van Hensbergen if (v9ses->maxdata != 9000) 2429e82cf6aSEric Van Hensbergen seq_printf(m, ",msize=%u", v9ses->maxdata); 2439e82cf6aSEric Van Hensbergen if (v9ses->afid != ~0) 2449e82cf6aSEric Van Hensbergen seq_printf(m, ",afid=%u", v9ses->afid); 2459e82cf6aSEric Van Hensbergen if (v9ses->proto == PROTO_UNIX) 2469e82cf6aSEric Van Hensbergen seq_puts(m, ",proto=unix"); 2479e82cf6aSEric Van Hensbergen if (v9ses->extended == 0) 2489e82cf6aSEric Van Hensbergen seq_puts(m, ",noextend"); 2499e82cf6aSEric Van Hensbergen if (v9ses->nodev == 1) 2509e82cf6aSEric Van Hensbergen seq_puts(m, ",nodevmap"); 2519e82cf6aSEric Van Hensbergen seq_printf(m, ",name=%s", v9ses->name); 2529e82cf6aSEric Van Hensbergen seq_printf(m, ",aname=%s", v9ses->remotename); 2539e82cf6aSEric Van Hensbergen seq_printf(m, ",uid=%u", v9ses->uid); 2549e82cf6aSEric Van Hensbergen seq_printf(m, ",gid=%u", v9ses->gid); 2559e82cf6aSEric Van Hensbergen return 0; 2569e82cf6aSEric Van Hensbergen } 2579e82cf6aSEric Van Hensbergen 258322b329aSEric Van Hensbergen static void 259322b329aSEric Van Hensbergen v9fs_umount_begin(struct super_block *sb) 260322b329aSEric Van Hensbergen { 261322b329aSEric Van Hensbergen struct v9fs_session_info *v9ses = sb->s_fs_info; 262322b329aSEric Van Hensbergen 263322b329aSEric Van Hensbergen v9fs_session_cancel(v9ses); 264322b329aSEric Van Hensbergen } 265322b329aSEric Van Hensbergen 2669e82cf6aSEric Van Hensbergen static struct super_operations v9fs_super_ops = { 2679e82cf6aSEric Van Hensbergen .statfs = simple_statfs, 2689e82cf6aSEric Van Hensbergen .clear_inode = v9fs_clear_inode, 2699e82cf6aSEric Van Hensbergen .show_options = v9fs_show_options, 270322b329aSEric Van Hensbergen .umount_begin = v9fs_umount_begin, 2719e82cf6aSEric Van Hensbergen }; 2729e82cf6aSEric Van Hensbergen 2739e82cf6aSEric Van Hensbergen struct file_system_type v9fs_fs_type = { 27467543e50SEric Van Hensbergen .name = "9p", 2759e82cf6aSEric Van Hensbergen .get_sb = v9fs_get_sb, 2769e82cf6aSEric Van Hensbergen .kill_sb = v9fs_kill_super, 2779e82cf6aSEric Van Hensbergen .owner = THIS_MODULE, 2789e82cf6aSEric Van Hensbergen }; 279