xref: /openbmc/linux/fs/orangefs/super.c (revision 1751e8a6cb935e555fcdbcb9ab4f0446e322ca3e)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21182fca3SMike Marshall /*
31182fca3SMike Marshall  * (C) 2001 Clemson University and The University of Chicago
41182fca3SMike Marshall  *
51182fca3SMike Marshall  * See COPYING in top-level directory.
61182fca3SMike Marshall  */
71182fca3SMike Marshall 
81182fca3SMike Marshall #include "protocol.h"
9575e9461SMike Marshall #include "orangefs-kernel.h"
10575e9461SMike Marshall #include "orangefs-bufmap.h"
111182fca3SMike Marshall 
121182fca3SMike Marshall #include <linux/parser.h>
131182fca3SMike Marshall 
148bb8aefdSYi Liu /* a cache for orangefs-inode objects (i.e. orangefs inode private data) */
158bb8aefdSYi Liu static struct kmem_cache *orangefs_inode_cache;
161182fca3SMike Marshall 
178bb8aefdSYi Liu /* list for storing orangefs specific superblocks in use */
188bb8aefdSYi Liu LIST_HEAD(orangefs_superblocks);
191182fca3SMike Marshall 
208bb8aefdSYi Liu DEFINE_SPINLOCK(orangefs_superblocks_lock);
211182fca3SMike Marshall 
221182fca3SMike Marshall enum {
231182fca3SMike Marshall 	Opt_intr,
241182fca3SMike Marshall 	Opt_acl,
251182fca3SMike Marshall 	Opt_local_lock,
261182fca3SMike Marshall 
271182fca3SMike Marshall 	Opt_err
281182fca3SMike Marshall };
291182fca3SMike Marshall 
301182fca3SMike Marshall static const match_table_t tokens = {
311182fca3SMike Marshall 	{ Opt_acl,		"acl" },
321182fca3SMike Marshall 	{ Opt_intr,		"intr" },
331182fca3SMike Marshall 	{ Opt_local_lock,	"local_lock" },
341182fca3SMike Marshall 	{ Opt_err,	NULL }
351182fca3SMike Marshall };
361182fca3SMike Marshall 
37482664ddSMartin Brandenburg uint64_t orangefs_features;
381182fca3SMike Marshall 
394dfdb713SDavid Howells static int orangefs_show_options(struct seq_file *m, struct dentry *root)
404dfdb713SDavid Howells {
414dfdb713SDavid Howells 	struct orangefs_sb_info_s *orangefs_sb = ORANGEFS_SB(root->d_sb);
424dfdb713SDavid Howells 
43*1751e8a6SLinus Torvalds 	if (root->d_sb->s_flags & SB_POSIXACL)
444dfdb713SDavid Howells 		seq_puts(m, ",acl");
454dfdb713SDavid Howells 	if (orangefs_sb->flags & ORANGEFS_OPT_INTR)
464dfdb713SDavid Howells 		seq_puts(m, ",intr");
474dfdb713SDavid Howells 	if (orangefs_sb->flags & ORANGEFS_OPT_LOCAL_LOCK)
484dfdb713SDavid Howells 		seq_puts(m, ",local_lock");
494dfdb713SDavid Howells 	return 0;
504dfdb713SDavid Howells }
514dfdb713SDavid Howells 
521182fca3SMike Marshall static int parse_mount_options(struct super_block *sb, char *options,
531182fca3SMike Marshall 		int silent)
541182fca3SMike Marshall {
558bb8aefdSYi Liu 	struct orangefs_sb_info_s *orangefs_sb = ORANGEFS_SB(sb);
561182fca3SMike Marshall 	substring_t args[MAX_OPT_ARGS];
571182fca3SMike Marshall 	char *p;
581182fca3SMike Marshall 
591182fca3SMike Marshall 	/*
601182fca3SMike Marshall 	 * Force any potential flags that might be set from the mount
611182fca3SMike Marshall 	 * to zero, ie, initialize to unset.
621182fca3SMike Marshall 	 */
63*1751e8a6SLinus Torvalds 	sb->s_flags &= ~SB_POSIXACL;
648bb8aefdSYi Liu 	orangefs_sb->flags &= ~ORANGEFS_OPT_INTR;
658bb8aefdSYi Liu 	orangefs_sb->flags &= ~ORANGEFS_OPT_LOCAL_LOCK;
661182fca3SMike Marshall 
671182fca3SMike Marshall 	while ((p = strsep(&options, ",")) != NULL) {
681182fca3SMike Marshall 		int token;
691182fca3SMike Marshall 
701182fca3SMike Marshall 		if (!*p)
711182fca3SMike Marshall 			continue;
721182fca3SMike Marshall 
731182fca3SMike Marshall 		token = match_token(p, tokens, args);
741182fca3SMike Marshall 		switch (token) {
751182fca3SMike Marshall 		case Opt_acl:
76*1751e8a6SLinus Torvalds 			sb->s_flags |= SB_POSIXACL;
771182fca3SMike Marshall 			break;
781182fca3SMike Marshall 		case Opt_intr:
798bb8aefdSYi Liu 			orangefs_sb->flags |= ORANGEFS_OPT_INTR;
801182fca3SMike Marshall 			break;
811182fca3SMike Marshall 		case Opt_local_lock:
828bb8aefdSYi Liu 			orangefs_sb->flags |= ORANGEFS_OPT_LOCAL_LOCK;
831182fca3SMike Marshall 			break;
841182fca3SMike Marshall 		default:
851182fca3SMike Marshall 			goto fail;
861182fca3SMike Marshall 		}
871182fca3SMike Marshall 	}
881182fca3SMike Marshall 
891182fca3SMike Marshall 	return 0;
901182fca3SMike Marshall fail:
911182fca3SMike Marshall 	if (!silent)
921182fca3SMike Marshall 		gossip_err("Error: mount option [%s] is not supported.\n", p);
931182fca3SMike Marshall 	return -EINVAL;
941182fca3SMike Marshall }
951182fca3SMike Marshall 
968bb8aefdSYi Liu static void orangefs_inode_cache_ctor(void *req)
971182fca3SMike Marshall {
988bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = req;
991182fca3SMike Marshall 
1008bb8aefdSYi Liu 	inode_init_once(&orangefs_inode->vfs_inode);
1018bb8aefdSYi Liu 	init_rwsem(&orangefs_inode->xattr_sem);
1021182fca3SMike Marshall }
1031182fca3SMike Marshall 
1048bb8aefdSYi Liu static struct inode *orangefs_alloc_inode(struct super_block *sb)
1051182fca3SMike Marshall {
1068bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode;
1071182fca3SMike Marshall 
1082d4cae0dSMike Marshall 	orangefs_inode = kmem_cache_alloc(orangefs_inode_cache, GFP_KERNEL);
10907a25853SMarkus Elfring 	if (!orangefs_inode)
1101182fca3SMike Marshall 		return NULL;
1111182fca3SMike Marshall 
1121182fca3SMike Marshall 	/*
1131182fca3SMike Marshall 	 * We want to clear everything except for rw_semaphore and the
1141182fca3SMike Marshall 	 * vfs_inode.
1151182fca3SMike Marshall 	 */
1168bb8aefdSYi Liu 	memset(&orangefs_inode->refn.khandle, 0, 16);
1178bb8aefdSYi Liu 	orangefs_inode->refn.fs_id = ORANGEFS_FS_ID_NULL;
1188bb8aefdSYi Liu 	orangefs_inode->last_failed_block_index_read = 0;
1198bb8aefdSYi Liu 	memset(orangefs_inode->link_target, 0, sizeof(orangefs_inode->link_target));
1201182fca3SMike Marshall 
1211182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
1228bb8aefdSYi Liu 		     "orangefs_alloc_inode: allocated %p\n",
1238bb8aefdSYi Liu 		     &orangefs_inode->vfs_inode);
1248bb8aefdSYi Liu 	return &orangefs_inode->vfs_inode;
1251182fca3SMike Marshall }
1261182fca3SMike Marshall 
1270695d7dcSPeter Zijlstra static void orangefs_i_callback(struct rcu_head *head)
1280695d7dcSPeter Zijlstra {
1290695d7dcSPeter Zijlstra 	struct inode *inode = container_of(head, struct inode, i_rcu);
1300695d7dcSPeter Zijlstra 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
1310695d7dcSPeter Zijlstra 	kmem_cache_free(orangefs_inode_cache, orangefs_inode);
1320695d7dcSPeter Zijlstra }
1330695d7dcSPeter Zijlstra 
1348bb8aefdSYi Liu static void orangefs_destroy_inode(struct inode *inode)
1351182fca3SMike Marshall {
1368bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
1371182fca3SMike Marshall 
1381182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
1391182fca3SMike Marshall 			"%s: deallocated %p destroying inode %pU\n",
1408bb8aefdSYi Liu 			__func__, orangefs_inode, get_khandle_from_ino(inode));
1411182fca3SMike Marshall 
1420695d7dcSPeter Zijlstra 	call_rcu(&inode->i_rcu, orangefs_i_callback);
1431182fca3SMike Marshall }
1441182fca3SMike Marshall 
1451182fca3SMike Marshall /*
1461182fca3SMike Marshall  * NOTE: information filled in here is typically reflected in the
1471182fca3SMike Marshall  * output of the system command 'df'
1481182fca3SMike Marshall */
1498bb8aefdSYi Liu static int orangefs_statfs(struct dentry *dentry, struct kstatfs *buf)
1501182fca3SMike Marshall {
1511182fca3SMike Marshall 	int ret = -ENOMEM;
1528bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op = NULL;
1531182fca3SMike Marshall 	int flags = 0;
1541182fca3SMike Marshall 	struct super_block *sb = NULL;
1551182fca3SMike Marshall 
1561182fca3SMike Marshall 	sb = dentry->d_sb;
1571182fca3SMike Marshall 
1581182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
1598bb8aefdSYi Liu 		     "orangefs_statfs: called on sb %p (fs_id is %d)\n",
1601182fca3SMike Marshall 		     sb,
1618bb8aefdSYi Liu 		     (int)(ORANGEFS_SB(sb)->fs_id));
1621182fca3SMike Marshall 
1638bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_STATFS);
1641182fca3SMike Marshall 	if (!new_op)
1651182fca3SMike Marshall 		return ret;
1668bb8aefdSYi Liu 	new_op->upcall.req.statfs.fs_id = ORANGEFS_SB(sb)->fs_id;
1671182fca3SMike Marshall 
1688bb8aefdSYi Liu 	if (ORANGEFS_SB(sb)->flags & ORANGEFS_OPT_INTR)
1698bb8aefdSYi Liu 		flags = ORANGEFS_OP_INTERRUPTIBLE;
1701182fca3SMike Marshall 
1718bb8aefdSYi Liu 	ret = service_operation(new_op, "orangefs_statfs", flags);
1721182fca3SMike Marshall 
1731182fca3SMike Marshall 	if (new_op->downcall.status < 0)
1741182fca3SMike Marshall 		goto out_op_release;
1751182fca3SMike Marshall 
1761182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
177be57366eSMike Marshall 		     "%s: got %ld blocks available | "
178be57366eSMike Marshall 		     "%ld blocks total | %ld block size | "
179be57366eSMike Marshall 		     "%ld files total | %ld files avail\n",
180be57366eSMike Marshall 		     __func__,
1811182fca3SMike Marshall 		     (long)new_op->downcall.resp.statfs.blocks_avail,
1821182fca3SMike Marshall 		     (long)new_op->downcall.resp.statfs.blocks_total,
183be57366eSMike Marshall 		     (long)new_op->downcall.resp.statfs.block_size,
184be57366eSMike Marshall 		     (long)new_op->downcall.resp.statfs.files_total,
185be57366eSMike Marshall 		     (long)new_op->downcall.resp.statfs.files_avail);
1861182fca3SMike Marshall 
1871182fca3SMike Marshall 	buf->f_type = sb->s_magic;
1888bb8aefdSYi Liu 	memcpy(&buf->f_fsid, &ORANGEFS_SB(sb)->fs_id, sizeof(buf->f_fsid));
1891182fca3SMike Marshall 	buf->f_bsize = new_op->downcall.resp.statfs.block_size;
19047b4948fSMartin Brandenburg 	buf->f_namelen = ORANGEFS_NAME_MAX;
1911182fca3SMike Marshall 
1921182fca3SMike Marshall 	buf->f_blocks = (sector_t) new_op->downcall.resp.statfs.blocks_total;
1931182fca3SMike Marshall 	buf->f_bfree = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
1941182fca3SMike Marshall 	buf->f_bavail = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
1951182fca3SMike Marshall 	buf->f_files = (sector_t) new_op->downcall.resp.statfs.files_total;
1961182fca3SMike Marshall 	buf->f_ffree = (sector_t) new_op->downcall.resp.statfs.files_avail;
1971182fca3SMike Marshall 	buf->f_frsize = sb->s_blocksize;
1981182fca3SMike Marshall 
1991182fca3SMike Marshall out_op_release:
2001182fca3SMike Marshall 	op_release(new_op);
2018bb8aefdSYi Liu 	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_statfs: returning %d\n", ret);
2021182fca3SMike Marshall 	return ret;
2031182fca3SMike Marshall }
2041182fca3SMike Marshall 
2051182fca3SMike Marshall /*
2061182fca3SMike Marshall  * Remount as initiated by VFS layer.  We just need to reparse the mount
2071182fca3SMike Marshall  * options, no need to signal pvfs2-client-core about it.
2081182fca3SMike Marshall  */
2098bb8aefdSYi Liu static int orangefs_remount_fs(struct super_block *sb, int *flags, char *data)
2101182fca3SMike Marshall {
2118bb8aefdSYi Liu 	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_remount_fs: called\n");
2121182fca3SMike Marshall 	return parse_mount_options(sb, data, 1);
2131182fca3SMike Marshall }
2141182fca3SMike Marshall 
2151182fca3SMike Marshall /*
2161182fca3SMike Marshall  * Remount as initiated by pvfs2-client-core on restart.  This is used to
2171182fca3SMike Marshall  * repopulate mount information left from previous pvfs2-client-core.
2181182fca3SMike Marshall  *
2191182fca3SMike Marshall  * the idea here is that given a valid superblock, we're
2201182fca3SMike Marshall  * re-initializing the user space client with the initial mount
2211182fca3SMike Marshall  * information specified when the super block was first initialized.
2221182fca3SMike Marshall  * this is very different than the first initialization/creation of a
2231182fca3SMike Marshall  * superblock.  we use the special service_priority_operation to make
2241182fca3SMike Marshall  * sure that the mount gets ahead of any other pending operation that
2251182fca3SMike Marshall  * is waiting for servicing.  this means that the pvfs2-client won't
2261182fca3SMike Marshall  * fail to start several times for all other pending operations before
2271182fca3SMike Marshall  * the client regains all of the mount information from us.
2281182fca3SMike Marshall  * NOTE: this function assumes that the request_mutex is already acquired!
2291182fca3SMike Marshall  */
23045996492SAl Viro int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb)
2311182fca3SMike Marshall {
2328bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op;
2331182fca3SMike Marshall 	int ret = -EINVAL;
2341182fca3SMike Marshall 
2358bb8aefdSYi Liu 	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_remount: called\n");
2361182fca3SMike Marshall 
2378bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
2381182fca3SMike Marshall 	if (!new_op)
2391182fca3SMike Marshall 		return -ENOMEM;
2408bb8aefdSYi Liu 	strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
24145996492SAl Viro 		orangefs_sb->devname,
2428bb8aefdSYi Liu 		ORANGEFS_MAX_SERVER_ADDR_LEN);
2431182fca3SMike Marshall 
2441182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
2458bb8aefdSYi Liu 		     "Attempting ORANGEFS Remount via host %s\n",
2468bb8aefdSYi Liu 		     new_op->upcall.req.fs_mount.orangefs_config_server);
2471182fca3SMike Marshall 
2481182fca3SMike Marshall 	/*
249adcf34a2SMike Marshall 	 * we assume that the calling function has already acquired the
2501182fca3SMike Marshall 	 * request_mutex to prevent other operations from bypassing
2511182fca3SMike Marshall 	 * this one
2521182fca3SMike Marshall 	 */
2538bb8aefdSYi Liu 	ret = service_operation(new_op, "orangefs_remount",
254adcf34a2SMike Marshall 		ORANGEFS_OP_PRIORITY | ORANGEFS_OP_NO_MUTEX);
2551182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
2568bb8aefdSYi Liu 		     "orangefs_remount: mount got return value of %d\n",
2571182fca3SMike Marshall 		     ret);
2581182fca3SMike Marshall 	if (ret == 0) {
2591182fca3SMike Marshall 		/*
2601182fca3SMike Marshall 		 * store the id assigned to this sb -- it's just a
2611182fca3SMike Marshall 		 * short-lived mapping that the system interface uses
2621182fca3SMike Marshall 		 * to map this superblock to a particular mount entry
2631182fca3SMike Marshall 		 */
26445996492SAl Viro 		orangefs_sb->id = new_op->downcall.resp.fs_mount.id;
26545996492SAl Viro 		orangefs_sb->mount_pending = 0;
2661182fca3SMike Marshall 	}
2671182fca3SMike Marshall 
2681182fca3SMike Marshall 	op_release(new_op);
269482664ddSMartin Brandenburg 
270f60fbdbfSMike Marshall 	if (orangefs_userspace_version >= 20906) {
271482664ddSMartin Brandenburg 		new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES);
272482664ddSMartin Brandenburg 		if (!new_op)
273482664ddSMartin Brandenburg 			return -ENOMEM;
274482664ddSMartin Brandenburg 		new_op->upcall.req.features.features = 0;
275cefdc26eSMartin Brandenburg 		ret = service_operation(new_op, "orangefs_features",
276cefdc26eSMartin Brandenburg 		    ORANGEFS_OP_PRIORITY | ORANGEFS_OP_NO_MUTEX);
277cefdc26eSMartin Brandenburg 		if (!ret)
278cefdc26eSMartin Brandenburg 			orangefs_features =
279cefdc26eSMartin Brandenburg 			    new_op->downcall.resp.features.features;
280cefdc26eSMartin Brandenburg 		else
281cefdc26eSMartin Brandenburg 			orangefs_features = 0;
282482664ddSMartin Brandenburg 		op_release(new_op);
283482664ddSMartin Brandenburg 	} else {
284482664ddSMartin Brandenburg 		orangefs_features = 0;
285482664ddSMartin Brandenburg 	}
286482664ddSMartin Brandenburg 
2871182fca3SMike Marshall 	return ret;
2881182fca3SMike Marshall }
2891182fca3SMike Marshall 
2901182fca3SMike Marshall int fsid_key_table_initialize(void)
2911182fca3SMike Marshall {
2921182fca3SMike Marshall 	return 0;
2931182fca3SMike Marshall }
2941182fca3SMike Marshall 
2951182fca3SMike Marshall void fsid_key_table_finalize(void)
2961182fca3SMike Marshall {
2971182fca3SMike Marshall }
2981182fca3SMike Marshall 
2998bb8aefdSYi Liu static const struct super_operations orangefs_s_ops = {
3008bb8aefdSYi Liu 	.alloc_inode = orangefs_alloc_inode,
3018bb8aefdSYi Liu 	.destroy_inode = orangefs_destroy_inode,
3021182fca3SMike Marshall 	.drop_inode = generic_delete_inode,
3038bb8aefdSYi Liu 	.statfs = orangefs_statfs,
3048bb8aefdSYi Liu 	.remount_fs = orangefs_remount_fs,
3054dfdb713SDavid Howells 	.show_options = orangefs_show_options,
3061182fca3SMike Marshall };
3071182fca3SMike Marshall 
3088bb8aefdSYi Liu static struct dentry *orangefs_fh_to_dentry(struct super_block *sb,
3091182fca3SMike Marshall 				  struct fid *fid,
3101182fca3SMike Marshall 				  int fh_len,
3111182fca3SMike Marshall 				  int fh_type)
3121182fca3SMike Marshall {
3138bb8aefdSYi Liu 	struct orangefs_object_kref refn;
3141182fca3SMike Marshall 
3151182fca3SMike Marshall 	if (fh_len < 5 || fh_type > 2)
3161182fca3SMike Marshall 		return NULL;
3171182fca3SMike Marshall 
3188bb8aefdSYi Liu 	ORANGEFS_khandle_from(&(refn.khandle), fid->raw, 16);
3191182fca3SMike Marshall 	refn.fs_id = (u32) fid->raw[4];
3201182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
3211182fca3SMike Marshall 		     "fh_to_dentry: handle %pU, fs_id %d\n",
3221182fca3SMike Marshall 		     &refn.khandle,
3231182fca3SMike Marshall 		     refn.fs_id);
3241182fca3SMike Marshall 
3258bb8aefdSYi Liu 	return d_obtain_alias(orangefs_iget(sb, &refn));
3261182fca3SMike Marshall }
3271182fca3SMike Marshall 
3288bb8aefdSYi Liu static int orangefs_encode_fh(struct inode *inode,
3291182fca3SMike Marshall 		    __u32 *fh,
3301182fca3SMike Marshall 		    int *max_len,
3311182fca3SMike Marshall 		    struct inode *parent)
3321182fca3SMike Marshall {
3331182fca3SMike Marshall 	int len = parent ? 10 : 5;
3341182fca3SMike Marshall 	int type = 1;
3358bb8aefdSYi Liu 	struct orangefs_object_kref refn;
3361182fca3SMike Marshall 
3371182fca3SMike Marshall 	if (*max_len < len) {
3381182fca3SMike Marshall 		gossip_lerr("fh buffer is too small for encoding\n");
3391182fca3SMike Marshall 		*max_len = len;
3401182fca3SMike Marshall 		type = 255;
3411182fca3SMike Marshall 		goto out;
3421182fca3SMike Marshall 	}
3431182fca3SMike Marshall 
3448bb8aefdSYi Liu 	refn = ORANGEFS_I(inode)->refn;
3458bb8aefdSYi Liu 	ORANGEFS_khandle_to(&refn.khandle, fh, 16);
3461182fca3SMike Marshall 	fh[4] = refn.fs_id;
3471182fca3SMike Marshall 
3481182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
3491182fca3SMike Marshall 		     "Encoding fh: handle %pU, fsid %u\n",
3501182fca3SMike Marshall 		     &refn.khandle,
3511182fca3SMike Marshall 		     refn.fs_id);
3521182fca3SMike Marshall 
3531182fca3SMike Marshall 
3541182fca3SMike Marshall 	if (parent) {
3558bb8aefdSYi Liu 		refn = ORANGEFS_I(parent)->refn;
3568bb8aefdSYi Liu 		ORANGEFS_khandle_to(&refn.khandle, (char *) fh + 20, 16);
3571182fca3SMike Marshall 		fh[9] = refn.fs_id;
3581182fca3SMike Marshall 
3591182fca3SMike Marshall 		type = 2;
3601182fca3SMike Marshall 		gossip_debug(GOSSIP_SUPER_DEBUG,
3611182fca3SMike Marshall 			     "Encoding parent: handle %pU, fsid %u\n",
3621182fca3SMike Marshall 			     &refn.khandle,
3631182fca3SMike Marshall 			     refn.fs_id);
3641182fca3SMike Marshall 	}
3651182fca3SMike Marshall 	*max_len = len;
3661182fca3SMike Marshall 
3671182fca3SMike Marshall out:
3681182fca3SMike Marshall 	return type;
3691182fca3SMike Marshall }
3701182fca3SMike Marshall 
371acaca36dSJulia Lawall static const struct export_operations orangefs_export_ops = {
3728bb8aefdSYi Liu 	.encode_fh = orangefs_encode_fh,
3738bb8aefdSYi Liu 	.fh_to_dentry = orangefs_fh_to_dentry,
3741182fca3SMike Marshall };
3751182fca3SMike Marshall 
3769d286b0dSMartin Brandenburg static int orangefs_unmount(int id, __s32 fs_id, const char *devname)
3779d286b0dSMartin Brandenburg {
3789d286b0dSMartin Brandenburg 	struct orangefs_kernel_op_s *op;
3799d286b0dSMartin Brandenburg 	int r;
3809d286b0dSMartin Brandenburg 	op = op_alloc(ORANGEFS_VFS_OP_FS_UMOUNT);
3819d286b0dSMartin Brandenburg 	if (!op)
3829d286b0dSMartin Brandenburg 		return -ENOMEM;
3839d286b0dSMartin Brandenburg 	op->upcall.req.fs_umount.id = id;
3849d286b0dSMartin Brandenburg 	op->upcall.req.fs_umount.fs_id = fs_id;
3859d286b0dSMartin Brandenburg 	strncpy(op->upcall.req.fs_umount.orangefs_config_server,
3869d286b0dSMartin Brandenburg 	    devname, ORANGEFS_MAX_SERVER_ADDR_LEN);
3879d286b0dSMartin Brandenburg 	r = service_operation(op, "orangefs_fs_umount", 0);
3889d286b0dSMartin Brandenburg 	/* Not much to do about an error here. */
3899d286b0dSMartin Brandenburg 	if (r)
3909d286b0dSMartin Brandenburg 		gossip_err("orangefs_unmount: service_operation %d\n", r);
3919d286b0dSMartin Brandenburg 	op_release(op);
3929d286b0dSMartin Brandenburg 	return r;
3939d286b0dSMartin Brandenburg }
3949d286b0dSMartin Brandenburg 
3958bb8aefdSYi Liu static int orangefs_fill_sb(struct super_block *sb,
3968bb8aefdSYi Liu 		struct orangefs_fs_mount_response *fs_mount,
3975c0dbbc6SAl Viro 		void *data, int silent)
3981182fca3SMike Marshall {
3991182fca3SMike Marshall 	int ret = -EINVAL;
4001182fca3SMike Marshall 	struct inode *root = NULL;
4011182fca3SMike Marshall 	struct dentry *root_dentry = NULL;
4028bb8aefdSYi Liu 	struct orangefs_object_kref root_object;
4031182fca3SMike Marshall 
4048bb8aefdSYi Liu 	/* alloc and init our private orangefs sb info */
40505d31c5cSMartin Brandenburg 	sb->s_fs_info = kzalloc(sizeof(struct orangefs_sb_info_s), GFP_KERNEL);
4068bb8aefdSYi Liu 	if (!ORANGEFS_SB(sb))
4071182fca3SMike Marshall 		return -ENOMEM;
4088bb8aefdSYi Liu 	ORANGEFS_SB(sb)->sb = sb;
4091182fca3SMike Marshall 
4108bb8aefdSYi Liu 	ORANGEFS_SB(sb)->root_khandle = fs_mount->root_khandle;
4118bb8aefdSYi Liu 	ORANGEFS_SB(sb)->fs_id = fs_mount->fs_id;
4128bb8aefdSYi Liu 	ORANGEFS_SB(sb)->id = fs_mount->id;
4131182fca3SMike Marshall 
4145c0dbbc6SAl Viro 	if (data) {
4155c0dbbc6SAl Viro 		ret = parse_mount_options(sb, data, silent);
4161182fca3SMike Marshall 		if (ret)
4171182fca3SMike Marshall 			return ret;
4181182fca3SMike Marshall 	}
4191182fca3SMike Marshall 
4201182fca3SMike Marshall 	/* Hang the xattr handlers off the superblock */
4218bb8aefdSYi Liu 	sb->s_xattr = orangefs_xattr_handlers;
4228bb8aefdSYi Liu 	sb->s_magic = ORANGEFS_SUPER_MAGIC;
4238bb8aefdSYi Liu 	sb->s_op = &orangefs_s_ops;
4248bb8aefdSYi Liu 	sb->s_d_op = &orangefs_dentry_operations;
4251182fca3SMike Marshall 
4268bb8aefdSYi Liu 	sb->s_blocksize = orangefs_bufmap_size_query();
4278bb8aefdSYi Liu 	sb->s_blocksize_bits = orangefs_bufmap_shift_query();
4281182fca3SMike Marshall 	sb->s_maxbytes = MAX_LFS_FILESIZE;
4291182fca3SMike Marshall 
4308bb8aefdSYi Liu 	root_object.khandle = ORANGEFS_SB(sb)->root_khandle;
4318bb8aefdSYi Liu 	root_object.fs_id = ORANGEFS_SB(sb)->fs_id;
4321182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
4331182fca3SMike Marshall 		     "get inode %pU, fsid %d\n",
4341182fca3SMike Marshall 		     &root_object.khandle,
4351182fca3SMike Marshall 		     root_object.fs_id);
4361182fca3SMike Marshall 
4378bb8aefdSYi Liu 	root = orangefs_iget(sb, &root_object);
4381182fca3SMike Marshall 	if (IS_ERR(root))
4391182fca3SMike Marshall 		return PTR_ERR(root);
4401182fca3SMike Marshall 
4411182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
4421182fca3SMike Marshall 		     "Allocated root inode [%p] with mode %x\n",
4431182fca3SMike Marshall 		     root,
4441182fca3SMike Marshall 		     root->i_mode);
4451182fca3SMike Marshall 
4461182fca3SMike Marshall 	/* allocates and places root dentry in dcache */
4471182fca3SMike Marshall 	root_dentry = d_make_root(root);
448b05a7851SAl Viro 	if (!root_dentry)
4491182fca3SMike Marshall 		return -ENOMEM;
4501182fca3SMike Marshall 
4518bb8aefdSYi Liu 	sb->s_export_op = &orangefs_export_ops;
4521182fca3SMike Marshall 	sb->s_root = root_dentry;
4531182fca3SMike Marshall 	return 0;
4541182fca3SMike Marshall }
4551182fca3SMike Marshall 
4568bb8aefdSYi Liu struct dentry *orangefs_mount(struct file_system_type *fst,
4571182fca3SMike Marshall 			   int flags,
4581182fca3SMike Marshall 			   const char *devname,
4591182fca3SMike Marshall 			   void *data)
4601182fca3SMike Marshall {
4611182fca3SMike Marshall 	int ret = -EINVAL;
4621182fca3SMike Marshall 	struct super_block *sb = ERR_PTR(-EINVAL);
4638bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op;
4641be21f86SMike Marshall 	struct dentry *d = ERR_PTR(-EINVAL);
4651182fca3SMike Marshall 
4661182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
4678bb8aefdSYi Liu 		     "orangefs_mount: called with devname %s\n",
4681182fca3SMike Marshall 		     devname);
4691182fca3SMike Marshall 
4701182fca3SMike Marshall 	if (!devname) {
4711182fca3SMike Marshall 		gossip_err("ERROR: device name not specified.\n");
4721182fca3SMike Marshall 		return ERR_PTR(-EINVAL);
4731182fca3SMike Marshall 	}
4741182fca3SMike Marshall 
4758bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
4761182fca3SMike Marshall 	if (!new_op)
4771182fca3SMike Marshall 		return ERR_PTR(-ENOMEM);
4781182fca3SMike Marshall 
4798bb8aefdSYi Liu 	strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
4801182fca3SMike Marshall 		devname,
4818bb8aefdSYi Liu 		ORANGEFS_MAX_SERVER_ADDR_LEN);
4821182fca3SMike Marshall 
4831182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
4848bb8aefdSYi Liu 		     "Attempting ORANGEFS Mount via host %s\n",
4858bb8aefdSYi Liu 		     new_op->upcall.req.fs_mount.orangefs_config_server);
4861182fca3SMike Marshall 
4878bb8aefdSYi Liu 	ret = service_operation(new_op, "orangefs_mount", 0);
4881182fca3SMike Marshall 	gossip_debug(GOSSIP_SUPER_DEBUG,
4898bb8aefdSYi Liu 		     "orangefs_mount: mount got return value of %d\n", ret);
4901182fca3SMike Marshall 	if (ret)
4911182fca3SMike Marshall 		goto free_op;
4921182fca3SMike Marshall 
4938bb8aefdSYi Liu 	if (new_op->downcall.resp.fs_mount.fs_id == ORANGEFS_FS_ID_NULL) {
4941182fca3SMike Marshall 		gossip_err("ERROR: Retrieved null fs_id\n");
4951182fca3SMike Marshall 		ret = -EINVAL;
4961182fca3SMike Marshall 		goto free_op;
4971182fca3SMike Marshall 	}
4981182fca3SMike Marshall 
4991be21f86SMike Marshall 	sb = sget(fst, NULL, set_anon_super, flags, NULL);
5001be21f86SMike Marshall 
5011be21f86SMike Marshall 	if (IS_ERR(sb)) {
5021be21f86SMike Marshall 		d = ERR_CAST(sb);
5039d286b0dSMartin Brandenburg 		orangefs_unmount(new_op->downcall.resp.fs_mount.id,
5049d286b0dSMartin Brandenburg 		    new_op->downcall.resp.fs_mount.fs_id, devname);
5051182fca3SMike Marshall 		goto free_op;
5061182fca3SMike Marshall 	}
5071182fca3SMike Marshall 
5088bb8aefdSYi Liu 	ret = orangefs_fill_sb(sb,
5095c0dbbc6SAl Viro 	      &new_op->downcall.resp.fs_mount, data,
510*1751e8a6SLinus Torvalds 	      flags & SB_SILENT ? 1 : 0);
5111be21f86SMike Marshall 
5121be21f86SMike Marshall 	if (ret) {
5131be21f86SMike Marshall 		d = ERR_PTR(ret);
5141ec1688cSMartin Brandenburg 		goto free_sb_and_op;
5151be21f86SMike Marshall 	}
5161182fca3SMike Marshall 
5171182fca3SMike Marshall 	/*
5181182fca3SMike Marshall 	 * on successful mount, store the devname and data
5191182fca3SMike Marshall 	 * used
5201182fca3SMike Marshall 	 */
5218bb8aefdSYi Liu 	strncpy(ORANGEFS_SB(sb)->devname,
5221182fca3SMike Marshall 		devname,
5238bb8aefdSYi Liu 		ORANGEFS_MAX_SERVER_ADDR_LEN);
5241182fca3SMike Marshall 
5251182fca3SMike Marshall 	/* mount_pending must be cleared */
5268bb8aefdSYi Liu 	ORANGEFS_SB(sb)->mount_pending = 0;
5271182fca3SMike Marshall 
5281182fca3SMike Marshall 	/*
5298bb8aefdSYi Liu 	 * finally, add this sb to our list of known orangefs
5301182fca3SMike Marshall 	 * sb's
5311182fca3SMike Marshall 	 */
53245996492SAl Viro 	gossip_debug(GOSSIP_SUPER_DEBUG,
53345996492SAl Viro 		     "Adding SB %p to orangefs superblocks\n",
53445996492SAl Viro 		     ORANGEFS_SB(sb));
53545996492SAl Viro 	spin_lock(&orangefs_superblocks_lock);
53645996492SAl Viro 	list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks);
53745996492SAl Viro 	spin_unlock(&orangefs_superblocks_lock);
5381182fca3SMike Marshall 	op_release(new_op);
539482664ddSMartin Brandenburg 
5401ec1688cSMartin Brandenburg 	/* Must be removed from the list now. */
5411ec1688cSMartin Brandenburg 	ORANGEFS_SB(sb)->no_list = 0;
5421ec1688cSMartin Brandenburg 
543f60fbdbfSMike Marshall 	if (orangefs_userspace_version >= 20906) {
544482664ddSMartin Brandenburg 		new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES);
545482664ddSMartin Brandenburg 		if (!new_op)
546482664ddSMartin Brandenburg 			return ERR_PTR(-ENOMEM);
547482664ddSMartin Brandenburg 		new_op->upcall.req.features.features = 0;
548482664ddSMartin Brandenburg 		ret = service_operation(new_op, "orangefs_features", 0);
549482664ddSMartin Brandenburg 		orangefs_features = new_op->downcall.resp.features.features;
550482664ddSMartin Brandenburg 		op_release(new_op);
551482664ddSMartin Brandenburg 	} else {
552482664ddSMartin Brandenburg 		orangefs_features = 0;
553482664ddSMartin Brandenburg 	}
554482664ddSMartin Brandenburg 
5551be21f86SMike Marshall 	return dget(sb->s_root);
5561182fca3SMike Marshall 
5571ec1688cSMartin Brandenburg free_sb_and_op:
5581ec1688cSMartin Brandenburg 	/* Will call orangefs_kill_sb with sb not in list. */
5591ec1688cSMartin Brandenburg 	ORANGEFS_SB(sb)->no_list = 1;
5609d286b0dSMartin Brandenburg 	/* ORANGEFS_VFS_OP_FS_UMOUNT is done by orangefs_kill_sb. */
5611ec1688cSMartin Brandenburg 	deactivate_locked_super(sb);
5621182fca3SMike Marshall free_op:
5638bb8aefdSYi Liu 	gossip_err("orangefs_mount: mount request failed with %d\n", ret);
5641182fca3SMike Marshall 	if (ret == -EINVAL) {
5658bb8aefdSYi Liu 		gossip_err("Ensure that all orangefs-servers have the same FS configuration files\n");
5661182fca3SMike Marshall 		gossip_err("Look at pvfs2-client-core log file (typically /tmp/pvfs2-client.log) for more details\n");
5671182fca3SMike Marshall 	}
5681182fca3SMike Marshall 
5691182fca3SMike Marshall 	op_release(new_op);
5701182fca3SMike Marshall 
5711be21f86SMike Marshall 	return d;
5721182fca3SMike Marshall }
5731182fca3SMike Marshall 
5748bb8aefdSYi Liu void orangefs_kill_sb(struct super_block *sb)
5751182fca3SMike Marshall {
5769d286b0dSMartin Brandenburg 	int r;
5778bb8aefdSYi Liu 	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_kill_sb: called\n");
5781182fca3SMike Marshall 
579524b1d30SAl Viro 	/* provided sb cleanup */
580524b1d30SAl Viro 	kill_anon_super(sb);
581524b1d30SAl Viro 
5821182fca3SMike Marshall 	/*
5831182fca3SMike Marshall 	 * issue the unmount to userspace to tell it to remove the
5841182fca3SMike Marshall 	 * dynamic mount info it has for this superblock
5851182fca3SMike Marshall 	 */
5869d286b0dSMartin Brandenburg 	r = orangefs_unmount(ORANGEFS_SB(sb)->id, ORANGEFS_SB(sb)->fs_id,
5879d286b0dSMartin Brandenburg 	    ORANGEFS_SB(sb)->devname);
5889d286b0dSMartin Brandenburg 	if (!r)
5899d286b0dSMartin Brandenburg 		ORANGEFS_SB(sb)->mount_pending = 1;
5901182fca3SMike Marshall 
5911ec1688cSMartin Brandenburg 	if (!ORANGEFS_SB(sb)->no_list) {
5928bb8aefdSYi Liu 		/* remove the sb from our list of orangefs specific sb's */
59345996492SAl Viro 		spin_lock(&orangefs_superblocks_lock);
5941ec1688cSMartin Brandenburg 		/* not list_del_init */
5951ec1688cSMartin Brandenburg 		__list_del_entry(&ORANGEFS_SB(sb)->list);
59645996492SAl Viro 		ORANGEFS_SB(sb)->list.prev = NULL;
59745996492SAl Viro 		spin_unlock(&orangefs_superblocks_lock);
5981ec1688cSMartin Brandenburg 	}
59945996492SAl Viro 
60045996492SAl Viro 	/*
60145996492SAl Viro 	 * make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us
60245996492SAl Viro 	 * gets completed before we free the dang thing.
60345996492SAl Viro 	 */
6041d503617SMartin Brandenburg 	mutex_lock(&orangefs_request_mutex);
6051d503617SMartin Brandenburg 	mutex_unlock(&orangefs_request_mutex);
6061182fca3SMike Marshall 
6078bb8aefdSYi Liu 	/* free the orangefs superblock private data */
6088bb8aefdSYi Liu 	kfree(ORANGEFS_SB(sb));
6091182fca3SMike Marshall }
6101182fca3SMike Marshall 
6118bb8aefdSYi Liu int orangefs_inode_cache_initialize(void)
6121182fca3SMike Marshall {
6138bb8aefdSYi Liu 	orangefs_inode_cache = kmem_cache_create("orangefs_inode_cache",
6148bb8aefdSYi Liu 					      sizeof(struct orangefs_inode_s),
6151182fca3SMike Marshall 					      0,
6168bb8aefdSYi Liu 					      ORANGEFS_CACHE_CREATE_FLAGS,
6178bb8aefdSYi Liu 					      orangefs_inode_cache_ctor);
6181182fca3SMike Marshall 
6198bb8aefdSYi Liu 	if (!orangefs_inode_cache) {
6208bb8aefdSYi Liu 		gossip_err("Cannot create orangefs_inode_cache\n");
6211182fca3SMike Marshall 		return -ENOMEM;
6221182fca3SMike Marshall 	}
6231182fca3SMike Marshall 	return 0;
6241182fca3SMike Marshall }
6251182fca3SMike Marshall 
6268bb8aefdSYi Liu int orangefs_inode_cache_finalize(void)
6271182fca3SMike Marshall {
6288bb8aefdSYi Liu 	kmem_cache_destroy(orangefs_inode_cache);
6291182fca3SMike Marshall 	return 0;
6301182fca3SMike Marshall }
631