Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Mar 24-27, 2025, special US time zones
Register
Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * (C) 2001 Clemson University and The University of Chicago
  4 *
  5 * See COPYING in top-level directory.
  6 */
  7
  8#include "protocol.h"
  9#include "orangefs-kernel.h"
 10#include "orangefs-bufmap.h"
 11
 12#include <linux/parser.h>
 13#include <linux/hashtable.h>
 14#include <linux/seq_file.h>
 15
 16/* a cache for orangefs-inode objects (i.e. orangefs inode private data) */
 17static struct kmem_cache *orangefs_inode_cache;
 18
 19/* list for storing orangefs specific superblocks in use */
 20LIST_HEAD(orangefs_superblocks);
 21
 22DEFINE_SPINLOCK(orangefs_superblocks_lock);
 23
 24enum {
 25	Opt_intr,
 26	Opt_acl,
 27	Opt_local_lock,
 28
 29	Opt_err
 30};
 31
 32static const match_table_t tokens = {
 33	{ Opt_acl,		"acl" },
 34	{ Opt_intr,		"intr" },
 35	{ Opt_local_lock,	"local_lock" },
 36	{ Opt_err,	NULL }
 37};
 38
 39uint64_t orangefs_features;
 40
 41static int orangefs_show_options(struct seq_file *m, struct dentry *root)
 42{
 43	struct orangefs_sb_info_s *orangefs_sb = ORANGEFS_SB(root->d_sb);
 44
 45	if (root->d_sb->s_flags & SB_POSIXACL)
 46		seq_puts(m, ",acl");
 47	if (orangefs_sb->flags & ORANGEFS_OPT_INTR)
 48		seq_puts(m, ",intr");
 49	if (orangefs_sb->flags & ORANGEFS_OPT_LOCAL_LOCK)
 50		seq_puts(m, ",local_lock");
 51	return 0;
 52}
 53
 54static int parse_mount_options(struct super_block *sb, char *options,
 55		int silent)
 56{
 57	struct orangefs_sb_info_s *orangefs_sb = ORANGEFS_SB(sb);
 58	substring_t args[MAX_OPT_ARGS];
 59	char *p;
 60
 61	/*
 62	 * Force any potential flags that might be set from the mount
 63	 * to zero, ie, initialize to unset.
 64	 */
 65	sb->s_flags &= ~SB_POSIXACL;
 66	orangefs_sb->flags &= ~ORANGEFS_OPT_INTR;
 67	orangefs_sb->flags &= ~ORANGEFS_OPT_LOCAL_LOCK;
 68
 69	while ((p = strsep(&options, ",")) != NULL) {
 70		int token;
 71
 72		if (!*p)
 73			continue;
 74
 75		token = match_token(p, tokens, args);
 76		switch (token) {
 77		case Opt_acl:
 78			sb->s_flags |= SB_POSIXACL;
 79			break;
 80		case Opt_intr:
 81			orangefs_sb->flags |= ORANGEFS_OPT_INTR;
 82			break;
 83		case Opt_local_lock:
 84			orangefs_sb->flags |= ORANGEFS_OPT_LOCAL_LOCK;
 85			break;
 86		default:
 87			goto fail;
 88		}
 89	}
 90
 91	return 0;
 92fail:
 93	if (!silent)
 94		gossip_err("Error: mount option [%s] is not supported.\n", p);
 95	return -EINVAL;
 96}
 97
 98static void orangefs_inode_cache_ctor(void *req)
 99{
100	struct orangefs_inode_s *orangefs_inode = req;
101
102	inode_init_once(&orangefs_inode->vfs_inode);
103	init_rwsem(&orangefs_inode->xattr_sem);
104}
105
106static struct inode *orangefs_alloc_inode(struct super_block *sb)
107{
108	struct orangefs_inode_s *orangefs_inode;
109
110	orangefs_inode = alloc_inode_sb(sb, orangefs_inode_cache, GFP_KERNEL);
111	if (!orangefs_inode)
112		return NULL;
113
114	/*
115	 * We want to clear everything except for rw_semaphore and the
116	 * vfs_inode.
117	 */
118	memset(&orangefs_inode->refn.khandle, 0, 16);
119	orangefs_inode->refn.fs_id = ORANGEFS_FS_ID_NULL;
120	orangefs_inode->last_failed_block_index_read = 0;
121	memset(orangefs_inode->link_target, 0, sizeof(orangefs_inode->link_target));
122
123	gossip_debug(GOSSIP_SUPER_DEBUG,
124		     "orangefs_alloc_inode: allocated %p\n",
125		     &orangefs_inode->vfs_inode);
126	return &orangefs_inode->vfs_inode;
127}
128
129static void orangefs_free_inode(struct inode *inode)
130{
131	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
132	struct orangefs_cached_xattr *cx;
133	struct hlist_node *tmp;
134	int i;
135
136	hash_for_each_safe(orangefs_inode->xattr_cache, i, tmp, cx, node) {
137		hlist_del(&cx->node);
138		kfree(cx);
139	}
140
141	kmem_cache_free(orangefs_inode_cache, orangefs_inode);
142}
143
144static void orangefs_destroy_inode(struct inode *inode)
145{
146	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
147
148	gossip_debug(GOSSIP_SUPER_DEBUG,
149			"%s: deallocated %p destroying inode %pU\n",
150			__func__, orangefs_inode, get_khandle_from_ino(inode));
151}
152
153static int orangefs_write_inode(struct inode *inode,
154				struct writeback_control *wbc)
155{
156	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_write_inode\n");
157	return orangefs_inode_setattr(inode);
158}
159
160/*
161 * NOTE: information filled in here is typically reflected in the
162 * output of the system command 'df'
163*/
164static int orangefs_statfs(struct dentry *dentry, struct kstatfs *buf)
165{
166	int ret = -ENOMEM;
167	struct orangefs_kernel_op_s *new_op = NULL;
168	int flags = 0;
169	struct super_block *sb = NULL;
170
171	sb = dentry->d_sb;
172
173	gossip_debug(GOSSIP_SUPER_DEBUG,
174			"%s: called on sb %p (fs_id is %d)\n",
175			__func__,
176			sb,
177			(int)(ORANGEFS_SB(sb)->fs_id));
178
179	new_op = op_alloc(ORANGEFS_VFS_OP_STATFS);
180	if (!new_op)
181		return ret;
182	new_op->upcall.req.statfs.fs_id = ORANGEFS_SB(sb)->fs_id;
183
184	if (ORANGEFS_SB(sb)->flags & ORANGEFS_OPT_INTR)
185		flags = ORANGEFS_OP_INTERRUPTIBLE;
186
187	ret = service_operation(new_op, "orangefs_statfs", flags);
188
189	if (new_op->downcall.status < 0)
190		goto out_op_release;
191
192	gossip_debug(GOSSIP_SUPER_DEBUG,
193		     "%s: got %ld blocks available | "
194		     "%ld blocks total | %ld block size | "
195		     "%ld files total | %ld files avail\n",
196		     __func__,
197		     (long)new_op->downcall.resp.statfs.blocks_avail,
198		     (long)new_op->downcall.resp.statfs.blocks_total,
199		     (long)new_op->downcall.resp.statfs.block_size,
200		     (long)new_op->downcall.resp.statfs.files_total,
201		     (long)new_op->downcall.resp.statfs.files_avail);
202
203	buf->f_type = sb->s_magic;
204	buf->f_fsid.val[0] = ORANGEFS_SB(sb)->fs_id;
205	buf->f_fsid.val[1] = ORANGEFS_SB(sb)->id;
206	buf->f_bsize = new_op->downcall.resp.statfs.block_size;
207	buf->f_namelen = ORANGEFS_NAME_MAX;
208
209	buf->f_blocks = (sector_t) new_op->downcall.resp.statfs.blocks_total;
210	buf->f_bfree = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
211	buf->f_bavail = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
212	buf->f_files = (sector_t) new_op->downcall.resp.statfs.files_total;
213	buf->f_ffree = (sector_t) new_op->downcall.resp.statfs.files_avail;
214	buf->f_frsize = 0;
215
216out_op_release:
217	op_release(new_op);
218	gossip_debug(GOSSIP_SUPER_DEBUG, "%s: returning %d\n", __func__, ret);
219	return ret;
220}
221
222/*
223 * Remount as initiated by VFS layer.  We just need to reparse the mount
224 * options, no need to signal pvfs2-client-core about it.
225 */
226static int orangefs_remount_fs(struct super_block *sb, int *flags, char *data)
227{
228	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_remount_fs: called\n");
229	return parse_mount_options(sb, data, 1);
230}
231
232/*
233 * Remount as initiated by pvfs2-client-core on restart.  This is used to
234 * repopulate mount information left from previous pvfs2-client-core.
235 *
236 * the idea here is that given a valid superblock, we're
237 * re-initializing the user space client with the initial mount
238 * information specified when the super block was first initialized.
239 * this is very different than the first initialization/creation of a
240 * superblock.  we use the special service_priority_operation to make
241 * sure that the mount gets ahead of any other pending operation that
242 * is waiting for servicing.  this means that the pvfs2-client won't
243 * fail to start several times for all other pending operations before
244 * the client regains all of the mount information from us.
245 * NOTE: this function assumes that the request_mutex is already acquired!
246 */
247int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb)
248{
249	struct orangefs_kernel_op_s *new_op;
250	int ret = -EINVAL;
251
252	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_remount: called\n");
253
254	new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
255	if (!new_op)
256		return -ENOMEM;
257	strscpy(new_op->upcall.req.fs_mount.orangefs_config_server,
258		orangefs_sb->devname);
 
259
260	gossip_debug(GOSSIP_SUPER_DEBUG,
261		     "Attempting ORANGEFS Remount via host %s\n",
262		     new_op->upcall.req.fs_mount.orangefs_config_server);
263
264	/*
265	 * we assume that the calling function has already acquired the
266	 * request_mutex to prevent other operations from bypassing
267	 * this one
268	 */
269	ret = service_operation(new_op, "orangefs_remount",
270		ORANGEFS_OP_PRIORITY | ORANGEFS_OP_NO_MUTEX);
271	gossip_debug(GOSSIP_SUPER_DEBUG,
272		     "orangefs_remount: mount got return value of %d\n",
273		     ret);
274	if (ret == 0) {
275		/*
276		 * store the id assigned to this sb -- it's just a
277		 * short-lived mapping that the system interface uses
278		 * to map this superblock to a particular mount entry
279		 */
280		orangefs_sb->id = new_op->downcall.resp.fs_mount.id;
281		orangefs_sb->mount_pending = 0;
282	}
283
284	op_release(new_op);
285
286	if (orangefs_userspace_version >= 20906) {
287		new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES);
288		if (!new_op)
289			return -ENOMEM;
290		new_op->upcall.req.features.features = 0;
291		ret = service_operation(new_op, "orangefs_features",
292		    ORANGEFS_OP_PRIORITY | ORANGEFS_OP_NO_MUTEX);
293		if (!ret)
294			orangefs_features =
295			    new_op->downcall.resp.features.features;
296		else
297			orangefs_features = 0;
298		op_release(new_op);
299	} else {
300		orangefs_features = 0;
301	}
302
303	return ret;
304}
305
306int fsid_key_table_initialize(void)
307{
308	return 0;
309}
310
311void fsid_key_table_finalize(void)
312{
313}
314
315static const struct super_operations orangefs_s_ops = {
316	.alloc_inode = orangefs_alloc_inode,
317	.free_inode = orangefs_free_inode,
318	.destroy_inode = orangefs_destroy_inode,
319	.write_inode = orangefs_write_inode,
320	.drop_inode = generic_delete_inode,
321	.statfs = orangefs_statfs,
322	.remount_fs = orangefs_remount_fs,
323	.show_options = orangefs_show_options,
324};
325
326static struct dentry *orangefs_fh_to_dentry(struct super_block *sb,
327				  struct fid *fid,
328				  int fh_len,
329				  int fh_type)
330{
331	struct orangefs_object_kref refn;
332
333	if (fh_len < 5 || fh_type > 2)
334		return NULL;
335
336	ORANGEFS_khandle_from(&(refn.khandle), fid->raw, 16);
337	refn.fs_id = (u32) fid->raw[4];
338	gossip_debug(GOSSIP_SUPER_DEBUG,
339		     "fh_to_dentry: handle %pU, fs_id %d\n",
340		     &refn.khandle,
341		     refn.fs_id);
342
343	return d_obtain_alias(orangefs_iget(sb, &refn));
344}
345
346static int orangefs_encode_fh(struct inode *inode,
347		    __u32 *fh,
348		    int *max_len,
349		    struct inode *parent)
350{
351	int len = parent ? 10 : 5;
352	int type = 1;
353	struct orangefs_object_kref refn;
354
355	if (*max_len < len) {
356		gossip_err("fh buffer is too small for encoding\n");
357		*max_len = len;
358		type = 255;
359		goto out;
360	}
361
362	refn = ORANGEFS_I(inode)->refn;
363	ORANGEFS_khandle_to(&refn.khandle, fh, 16);
364	fh[4] = refn.fs_id;
365
366	gossip_debug(GOSSIP_SUPER_DEBUG,
367		     "Encoding fh: handle %pU, fsid %u\n",
368		     &refn.khandle,
369		     refn.fs_id);
370
371
372	if (parent) {
373		refn = ORANGEFS_I(parent)->refn;
374		ORANGEFS_khandle_to(&refn.khandle, (char *) fh + 20, 16);
375		fh[9] = refn.fs_id;
376
377		type = 2;
378		gossip_debug(GOSSIP_SUPER_DEBUG,
379			     "Encoding parent: handle %pU, fsid %u\n",
380			     &refn.khandle,
381			     refn.fs_id);
382	}
383	*max_len = len;
384
385out:
386	return type;
387}
388
389static const struct export_operations orangefs_export_ops = {
390	.encode_fh = orangefs_encode_fh,
391	.fh_to_dentry = orangefs_fh_to_dentry,
392};
393
394static int orangefs_unmount(int id, __s32 fs_id, const char *devname)
395{
396	struct orangefs_kernel_op_s *op;
397	int r;
398	op = op_alloc(ORANGEFS_VFS_OP_FS_UMOUNT);
399	if (!op)
400		return -ENOMEM;
401	op->upcall.req.fs_umount.id = id;
402	op->upcall.req.fs_umount.fs_id = fs_id;
403	strscpy(op->upcall.req.fs_umount.orangefs_config_server, devname);
 
404	r = service_operation(op, "orangefs_fs_umount", 0);
405	/* Not much to do about an error here. */
406	if (r)
407		gossip_err("orangefs_unmount: service_operation %d\n", r);
408	op_release(op);
409	return r;
410}
411
412static int orangefs_fill_sb(struct super_block *sb,
413		struct orangefs_fs_mount_response *fs_mount,
414		void *data, int silent)
415{
416	int ret;
417	struct inode *root;
418	struct dentry *root_dentry;
419	struct orangefs_object_kref root_object;
420
421	ORANGEFS_SB(sb)->sb = sb;
422
423	ORANGEFS_SB(sb)->root_khandle = fs_mount->root_khandle;
424	ORANGEFS_SB(sb)->fs_id = fs_mount->fs_id;
425	ORANGEFS_SB(sb)->id = fs_mount->id;
426
427	if (data) {
428		ret = parse_mount_options(sb, data, silent);
429		if (ret)
430			return ret;
431	}
432
433	/* Hang the xattr handlers off the superblock */
434	sb->s_xattr = orangefs_xattr_handlers;
435	sb->s_magic = ORANGEFS_SUPER_MAGIC;
436	sb->s_op = &orangefs_s_ops;
437	sb->s_d_op = &orangefs_dentry_operations;
438
439	sb->s_blocksize = PAGE_SIZE;
440	sb->s_blocksize_bits = PAGE_SHIFT;
441	sb->s_maxbytes = MAX_LFS_FILESIZE;
442
443	ret = super_setup_bdi(sb);
444	if (ret)
445		return ret;
446
447	root_object.khandle = ORANGEFS_SB(sb)->root_khandle;
448	root_object.fs_id = ORANGEFS_SB(sb)->fs_id;
449	gossip_debug(GOSSIP_SUPER_DEBUG,
450		     "get inode %pU, fsid %d\n",
451		     &root_object.khandle,
452		     root_object.fs_id);
453
454	root = orangefs_iget(sb, &root_object);
455	if (IS_ERR(root))
456		return PTR_ERR(root);
457
458	gossip_debug(GOSSIP_SUPER_DEBUG,
459		     "Allocated root inode [%p] with mode %x\n",
460		     root,
461		     root->i_mode);
462
463	/* allocates and places root dentry in dcache */
464	root_dentry = d_make_root(root);
465	if (!root_dentry)
466		return -ENOMEM;
467
468	sb->s_export_op = &orangefs_export_ops;
469	sb->s_root = root_dentry;
470	return 0;
471}
472
473struct dentry *orangefs_mount(struct file_system_type *fst,
474			   int flags,
475			   const char *devname,
476			   void *data)
477{
478	int ret;
479	struct super_block *sb = ERR_PTR(-EINVAL);
480	struct orangefs_kernel_op_s *new_op;
481	struct dentry *d = ERR_PTR(-EINVAL);
482
483	gossip_debug(GOSSIP_SUPER_DEBUG,
484		     "orangefs_mount: called with devname %s\n",
485		     devname);
486
487	if (!devname) {
488		gossip_err("ERROR: device name not specified.\n");
489		return ERR_PTR(-EINVAL);
490	}
491
492	new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
493	if (!new_op)
494		return ERR_PTR(-ENOMEM);
495
496	strscpy(new_op->upcall.req.fs_mount.orangefs_config_server, devname);
 
 
497
498	gossip_debug(GOSSIP_SUPER_DEBUG,
499		     "Attempting ORANGEFS Mount via host %s\n",
500		     new_op->upcall.req.fs_mount.orangefs_config_server);
501
502	ret = service_operation(new_op, "orangefs_mount", 0);
503	gossip_debug(GOSSIP_SUPER_DEBUG,
504		     "orangefs_mount: mount got return value of %d\n", ret);
505	if (ret)
506		goto free_op;
507
508	if (new_op->downcall.resp.fs_mount.fs_id == ORANGEFS_FS_ID_NULL) {
509		gossip_err("ERROR: Retrieved null fs_id\n");
510		ret = -EINVAL;
511		goto free_op;
512	}
513
514	sb = sget(fst, NULL, set_anon_super, flags, NULL);
515
516	if (IS_ERR(sb)) {
517		d = ERR_CAST(sb);
518		orangefs_unmount(new_op->downcall.resp.fs_mount.id,
519		    new_op->downcall.resp.fs_mount.fs_id, devname);
520		goto free_op;
521	}
522
523	/* alloc and init our private orangefs sb info */
524	sb->s_fs_info = kzalloc(sizeof(struct orangefs_sb_info_s), GFP_KERNEL);
525	if (!ORANGEFS_SB(sb)) {
526		d = ERR_PTR(-ENOMEM);
527		goto free_op;
528	}
529
530	ret = orangefs_fill_sb(sb,
531	      &new_op->downcall.resp.fs_mount, data,
532	      flags & SB_SILENT ? 1 : 0);
533
534	if (ret) {
535		d = ERR_PTR(ret);
536		goto free_sb_and_op;
537	}
538
539	/*
540	 * on successful mount, store the devname and data
541	 * used
542	 */
543	strscpy(ORANGEFS_SB(sb)->devname, devname);
544
 
545
546	/* mount_pending must be cleared */
547	ORANGEFS_SB(sb)->mount_pending = 0;
548
549	/*
550	 * finally, add this sb to our list of known orangefs
551	 * sb's
552	 */
553	gossip_debug(GOSSIP_SUPER_DEBUG,
554		     "Adding SB %p to orangefs superblocks\n",
555		     ORANGEFS_SB(sb));
556	spin_lock(&orangefs_superblocks_lock);
557	list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks);
558	spin_unlock(&orangefs_superblocks_lock);
559	op_release(new_op);
560
561	/* Must be removed from the list now. */
562	ORANGEFS_SB(sb)->no_list = 0;
563
564	if (orangefs_userspace_version >= 20906) {
565		new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES);
566		if (!new_op)
567			return ERR_PTR(-ENOMEM);
568		new_op->upcall.req.features.features = 0;
569		ret = service_operation(new_op, "orangefs_features", 0);
570		orangefs_features = new_op->downcall.resp.features.features;
571		op_release(new_op);
572	} else {
573		orangefs_features = 0;
574	}
575
576	return dget(sb->s_root);
577
578free_sb_and_op:
579	/* Will call orangefs_kill_sb with sb not in list. */
580	ORANGEFS_SB(sb)->no_list = 1;
581	/* ORANGEFS_VFS_OP_FS_UMOUNT is done by orangefs_kill_sb. */
582	deactivate_locked_super(sb);
583free_op:
584	gossip_err("orangefs_mount: mount request failed with %d\n", ret);
585	if (ret == -EINVAL) {
586		gossip_err("Ensure that all orangefs-servers have the same FS configuration files\n");
587		gossip_err("Look at pvfs2-client-core log file (typically /tmp/pvfs2-client.log) for more details\n");
588	}
589
590	op_release(new_op);
591
592	return d;
593}
594
595void orangefs_kill_sb(struct super_block *sb)
596{
597	int r;
598	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_kill_sb: called\n");
599
600	/* provided sb cleanup */
601	kill_anon_super(sb);
602
603	if (!ORANGEFS_SB(sb)) {
604		mutex_lock(&orangefs_request_mutex);
605		mutex_unlock(&orangefs_request_mutex);
606		return;
607	}
608	/*
609	 * issue the unmount to userspace to tell it to remove the
610	 * dynamic mount info it has for this superblock
611	 */
612	r = orangefs_unmount(ORANGEFS_SB(sb)->id, ORANGEFS_SB(sb)->fs_id,
613	    ORANGEFS_SB(sb)->devname);
614	if (!r)
615		ORANGEFS_SB(sb)->mount_pending = 1;
616
617	if (!ORANGEFS_SB(sb)->no_list) {
618		/* remove the sb from our list of orangefs specific sb's */
619		spin_lock(&orangefs_superblocks_lock);
620		/* not list_del_init */
621		__list_del_entry(&ORANGEFS_SB(sb)->list);
622		ORANGEFS_SB(sb)->list.prev = NULL;
623		spin_unlock(&orangefs_superblocks_lock);
624	}
625
626	/*
627	 * make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us
628	 * gets completed before we free the dang thing.
629	 */
630	mutex_lock(&orangefs_request_mutex);
631	mutex_unlock(&orangefs_request_mutex);
632
633	/* free the orangefs superblock private data */
634	kfree(ORANGEFS_SB(sb));
635}
636
637int orangefs_inode_cache_initialize(void)
638{
639	orangefs_inode_cache = kmem_cache_create_usercopy(
640					"orangefs_inode_cache",
641					sizeof(struct orangefs_inode_s),
642					0,
643					0,
644					offsetof(struct orangefs_inode_s,
645						link_target),
646					sizeof_field(struct orangefs_inode_s,
647						link_target),
648					orangefs_inode_cache_ctor);
649
650	if (!orangefs_inode_cache) {
651		gossip_err("Cannot create orangefs_inode_cache\n");
652		return -ENOMEM;
653	}
654	return 0;
655}
656
657int orangefs_inode_cache_finalize(void)
658{
659	kmem_cache_destroy(orangefs_inode_cache);
660	return 0;
661}
v5.14.15
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * (C) 2001 Clemson University and The University of Chicago
  4 *
  5 * See COPYING in top-level directory.
  6 */
  7
  8#include "protocol.h"
  9#include "orangefs-kernel.h"
 10#include "orangefs-bufmap.h"
 11
 12#include <linux/parser.h>
 13#include <linux/hashtable.h>
 
 14
 15/* a cache for orangefs-inode objects (i.e. orangefs inode private data) */
 16static struct kmem_cache *orangefs_inode_cache;
 17
 18/* list for storing orangefs specific superblocks in use */
 19LIST_HEAD(orangefs_superblocks);
 20
 21DEFINE_SPINLOCK(orangefs_superblocks_lock);
 22
 23enum {
 24	Opt_intr,
 25	Opt_acl,
 26	Opt_local_lock,
 27
 28	Opt_err
 29};
 30
 31static const match_table_t tokens = {
 32	{ Opt_acl,		"acl" },
 33	{ Opt_intr,		"intr" },
 34	{ Opt_local_lock,	"local_lock" },
 35	{ Opt_err,	NULL }
 36};
 37
 38uint64_t orangefs_features;
 39
 40static int orangefs_show_options(struct seq_file *m, struct dentry *root)
 41{
 42	struct orangefs_sb_info_s *orangefs_sb = ORANGEFS_SB(root->d_sb);
 43
 44	if (root->d_sb->s_flags & SB_POSIXACL)
 45		seq_puts(m, ",acl");
 46	if (orangefs_sb->flags & ORANGEFS_OPT_INTR)
 47		seq_puts(m, ",intr");
 48	if (orangefs_sb->flags & ORANGEFS_OPT_LOCAL_LOCK)
 49		seq_puts(m, ",local_lock");
 50	return 0;
 51}
 52
 53static int parse_mount_options(struct super_block *sb, char *options,
 54		int silent)
 55{
 56	struct orangefs_sb_info_s *orangefs_sb = ORANGEFS_SB(sb);
 57	substring_t args[MAX_OPT_ARGS];
 58	char *p;
 59
 60	/*
 61	 * Force any potential flags that might be set from the mount
 62	 * to zero, ie, initialize to unset.
 63	 */
 64	sb->s_flags &= ~SB_POSIXACL;
 65	orangefs_sb->flags &= ~ORANGEFS_OPT_INTR;
 66	orangefs_sb->flags &= ~ORANGEFS_OPT_LOCAL_LOCK;
 67
 68	while ((p = strsep(&options, ",")) != NULL) {
 69		int token;
 70
 71		if (!*p)
 72			continue;
 73
 74		token = match_token(p, tokens, args);
 75		switch (token) {
 76		case Opt_acl:
 77			sb->s_flags |= SB_POSIXACL;
 78			break;
 79		case Opt_intr:
 80			orangefs_sb->flags |= ORANGEFS_OPT_INTR;
 81			break;
 82		case Opt_local_lock:
 83			orangefs_sb->flags |= ORANGEFS_OPT_LOCAL_LOCK;
 84			break;
 85		default:
 86			goto fail;
 87		}
 88	}
 89
 90	return 0;
 91fail:
 92	if (!silent)
 93		gossip_err("Error: mount option [%s] is not supported.\n", p);
 94	return -EINVAL;
 95}
 96
 97static void orangefs_inode_cache_ctor(void *req)
 98{
 99	struct orangefs_inode_s *orangefs_inode = req;
100
101	inode_init_once(&orangefs_inode->vfs_inode);
102	init_rwsem(&orangefs_inode->xattr_sem);
103}
104
105static struct inode *orangefs_alloc_inode(struct super_block *sb)
106{
107	struct orangefs_inode_s *orangefs_inode;
108
109	orangefs_inode = kmem_cache_alloc(orangefs_inode_cache, GFP_KERNEL);
110	if (!orangefs_inode)
111		return NULL;
112
113	/*
114	 * We want to clear everything except for rw_semaphore and the
115	 * vfs_inode.
116	 */
117	memset(&orangefs_inode->refn.khandle, 0, 16);
118	orangefs_inode->refn.fs_id = ORANGEFS_FS_ID_NULL;
119	orangefs_inode->last_failed_block_index_read = 0;
120	memset(orangefs_inode->link_target, 0, sizeof(orangefs_inode->link_target));
121
122	gossip_debug(GOSSIP_SUPER_DEBUG,
123		     "orangefs_alloc_inode: allocated %p\n",
124		     &orangefs_inode->vfs_inode);
125	return &orangefs_inode->vfs_inode;
126}
127
128static void orangefs_free_inode(struct inode *inode)
129{
130	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
131	struct orangefs_cached_xattr *cx;
132	struct hlist_node *tmp;
133	int i;
134
135	hash_for_each_safe(orangefs_inode->xattr_cache, i, tmp, cx, node) {
136		hlist_del(&cx->node);
137		kfree(cx);
138	}
139
140	kmem_cache_free(orangefs_inode_cache, orangefs_inode);
141}
142
143static void orangefs_destroy_inode(struct inode *inode)
144{
145	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
146
147	gossip_debug(GOSSIP_SUPER_DEBUG,
148			"%s: deallocated %p destroying inode %pU\n",
149			__func__, orangefs_inode, get_khandle_from_ino(inode));
150}
151
152static int orangefs_write_inode(struct inode *inode,
153				struct writeback_control *wbc)
154{
155	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_write_inode\n");
156	return orangefs_inode_setattr(inode);
157}
158
159/*
160 * NOTE: information filled in here is typically reflected in the
161 * output of the system command 'df'
162*/
163static int orangefs_statfs(struct dentry *dentry, struct kstatfs *buf)
164{
165	int ret = -ENOMEM;
166	struct orangefs_kernel_op_s *new_op = NULL;
167	int flags = 0;
168	struct super_block *sb = NULL;
169
170	sb = dentry->d_sb;
171
172	gossip_debug(GOSSIP_SUPER_DEBUG,
173			"%s: called on sb %p (fs_id is %d)\n",
174			__func__,
175			sb,
176			(int)(ORANGEFS_SB(sb)->fs_id));
177
178	new_op = op_alloc(ORANGEFS_VFS_OP_STATFS);
179	if (!new_op)
180		return ret;
181	new_op->upcall.req.statfs.fs_id = ORANGEFS_SB(sb)->fs_id;
182
183	if (ORANGEFS_SB(sb)->flags & ORANGEFS_OPT_INTR)
184		flags = ORANGEFS_OP_INTERRUPTIBLE;
185
186	ret = service_operation(new_op, "orangefs_statfs", flags);
187
188	if (new_op->downcall.status < 0)
189		goto out_op_release;
190
191	gossip_debug(GOSSIP_SUPER_DEBUG,
192		     "%s: got %ld blocks available | "
193		     "%ld blocks total | %ld block size | "
194		     "%ld files total | %ld files avail\n",
195		     __func__,
196		     (long)new_op->downcall.resp.statfs.blocks_avail,
197		     (long)new_op->downcall.resp.statfs.blocks_total,
198		     (long)new_op->downcall.resp.statfs.block_size,
199		     (long)new_op->downcall.resp.statfs.files_total,
200		     (long)new_op->downcall.resp.statfs.files_avail);
201
202	buf->f_type = sb->s_magic;
203	memcpy(&buf->f_fsid, &ORANGEFS_SB(sb)->fs_id, sizeof(buf->f_fsid));
 
204	buf->f_bsize = new_op->downcall.resp.statfs.block_size;
205	buf->f_namelen = ORANGEFS_NAME_MAX;
206
207	buf->f_blocks = (sector_t) new_op->downcall.resp.statfs.blocks_total;
208	buf->f_bfree = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
209	buf->f_bavail = (sector_t) new_op->downcall.resp.statfs.blocks_avail;
210	buf->f_files = (sector_t) new_op->downcall.resp.statfs.files_total;
211	buf->f_ffree = (sector_t) new_op->downcall.resp.statfs.files_avail;
212	buf->f_frsize = 0;
213
214out_op_release:
215	op_release(new_op);
216	gossip_debug(GOSSIP_SUPER_DEBUG, "%s: returning %d\n", __func__, ret);
217	return ret;
218}
219
220/*
221 * Remount as initiated by VFS layer.  We just need to reparse the mount
222 * options, no need to signal pvfs2-client-core about it.
223 */
224static int orangefs_remount_fs(struct super_block *sb, int *flags, char *data)
225{
226	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_remount_fs: called\n");
227	return parse_mount_options(sb, data, 1);
228}
229
230/*
231 * Remount as initiated by pvfs2-client-core on restart.  This is used to
232 * repopulate mount information left from previous pvfs2-client-core.
233 *
234 * the idea here is that given a valid superblock, we're
235 * re-initializing the user space client with the initial mount
236 * information specified when the super block was first initialized.
237 * this is very different than the first initialization/creation of a
238 * superblock.  we use the special service_priority_operation to make
239 * sure that the mount gets ahead of any other pending operation that
240 * is waiting for servicing.  this means that the pvfs2-client won't
241 * fail to start several times for all other pending operations before
242 * the client regains all of the mount information from us.
243 * NOTE: this function assumes that the request_mutex is already acquired!
244 */
245int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb)
246{
247	struct orangefs_kernel_op_s *new_op;
248	int ret = -EINVAL;
249
250	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_remount: called\n");
251
252	new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
253	if (!new_op)
254		return -ENOMEM;
255	strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
256		orangefs_sb->devname,
257		ORANGEFS_MAX_SERVER_ADDR_LEN);
258
259	gossip_debug(GOSSIP_SUPER_DEBUG,
260		     "Attempting ORANGEFS Remount via host %s\n",
261		     new_op->upcall.req.fs_mount.orangefs_config_server);
262
263	/*
264	 * we assume that the calling function has already acquired the
265	 * request_mutex to prevent other operations from bypassing
266	 * this one
267	 */
268	ret = service_operation(new_op, "orangefs_remount",
269		ORANGEFS_OP_PRIORITY | ORANGEFS_OP_NO_MUTEX);
270	gossip_debug(GOSSIP_SUPER_DEBUG,
271		     "orangefs_remount: mount got return value of %d\n",
272		     ret);
273	if (ret == 0) {
274		/*
275		 * store the id assigned to this sb -- it's just a
276		 * short-lived mapping that the system interface uses
277		 * to map this superblock to a particular mount entry
278		 */
279		orangefs_sb->id = new_op->downcall.resp.fs_mount.id;
280		orangefs_sb->mount_pending = 0;
281	}
282
283	op_release(new_op);
284
285	if (orangefs_userspace_version >= 20906) {
286		new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES);
287		if (!new_op)
288			return -ENOMEM;
289		new_op->upcall.req.features.features = 0;
290		ret = service_operation(new_op, "orangefs_features",
291		    ORANGEFS_OP_PRIORITY | ORANGEFS_OP_NO_MUTEX);
292		if (!ret)
293			orangefs_features =
294			    new_op->downcall.resp.features.features;
295		else
296			orangefs_features = 0;
297		op_release(new_op);
298	} else {
299		orangefs_features = 0;
300	}
301
302	return ret;
303}
304
305int fsid_key_table_initialize(void)
306{
307	return 0;
308}
309
310void fsid_key_table_finalize(void)
311{
312}
313
314static const struct super_operations orangefs_s_ops = {
315	.alloc_inode = orangefs_alloc_inode,
316	.free_inode = orangefs_free_inode,
317	.destroy_inode = orangefs_destroy_inode,
318	.write_inode = orangefs_write_inode,
319	.drop_inode = generic_delete_inode,
320	.statfs = orangefs_statfs,
321	.remount_fs = orangefs_remount_fs,
322	.show_options = orangefs_show_options,
323};
324
325static struct dentry *orangefs_fh_to_dentry(struct super_block *sb,
326				  struct fid *fid,
327				  int fh_len,
328				  int fh_type)
329{
330	struct orangefs_object_kref refn;
331
332	if (fh_len < 5 || fh_type > 2)
333		return NULL;
334
335	ORANGEFS_khandle_from(&(refn.khandle), fid->raw, 16);
336	refn.fs_id = (u32) fid->raw[4];
337	gossip_debug(GOSSIP_SUPER_DEBUG,
338		     "fh_to_dentry: handle %pU, fs_id %d\n",
339		     &refn.khandle,
340		     refn.fs_id);
341
342	return d_obtain_alias(orangefs_iget(sb, &refn));
343}
344
345static int orangefs_encode_fh(struct inode *inode,
346		    __u32 *fh,
347		    int *max_len,
348		    struct inode *parent)
349{
350	int len = parent ? 10 : 5;
351	int type = 1;
352	struct orangefs_object_kref refn;
353
354	if (*max_len < len) {
355		gossip_err("fh buffer is too small for encoding\n");
356		*max_len = len;
357		type = 255;
358		goto out;
359	}
360
361	refn = ORANGEFS_I(inode)->refn;
362	ORANGEFS_khandle_to(&refn.khandle, fh, 16);
363	fh[4] = refn.fs_id;
364
365	gossip_debug(GOSSIP_SUPER_DEBUG,
366		     "Encoding fh: handle %pU, fsid %u\n",
367		     &refn.khandle,
368		     refn.fs_id);
369
370
371	if (parent) {
372		refn = ORANGEFS_I(parent)->refn;
373		ORANGEFS_khandle_to(&refn.khandle, (char *) fh + 20, 16);
374		fh[9] = refn.fs_id;
375
376		type = 2;
377		gossip_debug(GOSSIP_SUPER_DEBUG,
378			     "Encoding parent: handle %pU, fsid %u\n",
379			     &refn.khandle,
380			     refn.fs_id);
381	}
382	*max_len = len;
383
384out:
385	return type;
386}
387
388static const struct export_operations orangefs_export_ops = {
389	.encode_fh = orangefs_encode_fh,
390	.fh_to_dentry = orangefs_fh_to_dentry,
391};
392
393static int orangefs_unmount(int id, __s32 fs_id, const char *devname)
394{
395	struct orangefs_kernel_op_s *op;
396	int r;
397	op = op_alloc(ORANGEFS_VFS_OP_FS_UMOUNT);
398	if (!op)
399		return -ENOMEM;
400	op->upcall.req.fs_umount.id = id;
401	op->upcall.req.fs_umount.fs_id = fs_id;
402	strncpy(op->upcall.req.fs_umount.orangefs_config_server,
403	    devname, ORANGEFS_MAX_SERVER_ADDR_LEN - 1);
404	r = service_operation(op, "orangefs_fs_umount", 0);
405	/* Not much to do about an error here. */
406	if (r)
407		gossip_err("orangefs_unmount: service_operation %d\n", r);
408	op_release(op);
409	return r;
410}
411
412static int orangefs_fill_sb(struct super_block *sb,
413		struct orangefs_fs_mount_response *fs_mount,
414		void *data, int silent)
415{
416	int ret;
417	struct inode *root;
418	struct dentry *root_dentry;
419	struct orangefs_object_kref root_object;
420
421	ORANGEFS_SB(sb)->sb = sb;
422
423	ORANGEFS_SB(sb)->root_khandle = fs_mount->root_khandle;
424	ORANGEFS_SB(sb)->fs_id = fs_mount->fs_id;
425	ORANGEFS_SB(sb)->id = fs_mount->id;
426
427	if (data) {
428		ret = parse_mount_options(sb, data, silent);
429		if (ret)
430			return ret;
431	}
432
433	/* Hang the xattr handlers off the superblock */
434	sb->s_xattr = orangefs_xattr_handlers;
435	sb->s_magic = ORANGEFS_SUPER_MAGIC;
436	sb->s_op = &orangefs_s_ops;
437	sb->s_d_op = &orangefs_dentry_operations;
438
439	sb->s_blocksize = PAGE_SIZE;
440	sb->s_blocksize_bits = PAGE_SHIFT;
441	sb->s_maxbytes = MAX_LFS_FILESIZE;
442
443	ret = super_setup_bdi(sb);
444	if (ret)
445		return ret;
446
447	root_object.khandle = ORANGEFS_SB(sb)->root_khandle;
448	root_object.fs_id = ORANGEFS_SB(sb)->fs_id;
449	gossip_debug(GOSSIP_SUPER_DEBUG,
450		     "get inode %pU, fsid %d\n",
451		     &root_object.khandle,
452		     root_object.fs_id);
453
454	root = orangefs_iget(sb, &root_object);
455	if (IS_ERR(root))
456		return PTR_ERR(root);
457
458	gossip_debug(GOSSIP_SUPER_DEBUG,
459		     "Allocated root inode [%p] with mode %x\n",
460		     root,
461		     root->i_mode);
462
463	/* allocates and places root dentry in dcache */
464	root_dentry = d_make_root(root);
465	if (!root_dentry)
466		return -ENOMEM;
467
468	sb->s_export_op = &orangefs_export_ops;
469	sb->s_root = root_dentry;
470	return 0;
471}
472
473struct dentry *orangefs_mount(struct file_system_type *fst,
474			   int flags,
475			   const char *devname,
476			   void *data)
477{
478	int ret = -EINVAL;
479	struct super_block *sb = ERR_PTR(-EINVAL);
480	struct orangefs_kernel_op_s *new_op;
481	struct dentry *d = ERR_PTR(-EINVAL);
482
483	gossip_debug(GOSSIP_SUPER_DEBUG,
484		     "orangefs_mount: called with devname %s\n",
485		     devname);
486
487	if (!devname) {
488		gossip_err("ERROR: device name not specified.\n");
489		return ERR_PTR(-EINVAL);
490	}
491
492	new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT);
493	if (!new_op)
494		return ERR_PTR(-ENOMEM);
495
496	strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
497		devname,
498		ORANGEFS_MAX_SERVER_ADDR_LEN - 1);
499
500	gossip_debug(GOSSIP_SUPER_DEBUG,
501		     "Attempting ORANGEFS Mount via host %s\n",
502		     new_op->upcall.req.fs_mount.orangefs_config_server);
503
504	ret = service_operation(new_op, "orangefs_mount", 0);
505	gossip_debug(GOSSIP_SUPER_DEBUG,
506		     "orangefs_mount: mount got return value of %d\n", ret);
507	if (ret)
508		goto free_op;
509
510	if (new_op->downcall.resp.fs_mount.fs_id == ORANGEFS_FS_ID_NULL) {
511		gossip_err("ERROR: Retrieved null fs_id\n");
512		ret = -EINVAL;
513		goto free_op;
514	}
515
516	sb = sget(fst, NULL, set_anon_super, flags, NULL);
517
518	if (IS_ERR(sb)) {
519		d = ERR_CAST(sb);
520		orangefs_unmount(new_op->downcall.resp.fs_mount.id,
521		    new_op->downcall.resp.fs_mount.fs_id, devname);
522		goto free_op;
523	}
524
525	/* alloc and init our private orangefs sb info */
526	sb->s_fs_info = kzalloc(sizeof(struct orangefs_sb_info_s), GFP_KERNEL);
527	if (!ORANGEFS_SB(sb)) {
528		d = ERR_PTR(-ENOMEM);
529		goto free_op;
530	}
531
532	ret = orangefs_fill_sb(sb,
533	      &new_op->downcall.resp.fs_mount, data,
534	      flags & SB_SILENT ? 1 : 0);
535
536	if (ret) {
537		d = ERR_PTR(ret);
538		goto free_sb_and_op;
539	}
540
541	/*
542	 * on successful mount, store the devname and data
543	 * used
544	 */
545	strncpy(ORANGEFS_SB(sb)->devname,
546		devname,
547		ORANGEFS_MAX_SERVER_ADDR_LEN - 1);
548
549	/* mount_pending must be cleared */
550	ORANGEFS_SB(sb)->mount_pending = 0;
551
552	/*
553	 * finally, add this sb to our list of known orangefs
554	 * sb's
555	 */
556	gossip_debug(GOSSIP_SUPER_DEBUG,
557		     "Adding SB %p to orangefs superblocks\n",
558		     ORANGEFS_SB(sb));
559	spin_lock(&orangefs_superblocks_lock);
560	list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks);
561	spin_unlock(&orangefs_superblocks_lock);
562	op_release(new_op);
563
564	/* Must be removed from the list now. */
565	ORANGEFS_SB(sb)->no_list = 0;
566
567	if (orangefs_userspace_version >= 20906) {
568		new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES);
569		if (!new_op)
570			return ERR_PTR(-ENOMEM);
571		new_op->upcall.req.features.features = 0;
572		ret = service_operation(new_op, "orangefs_features", 0);
573		orangefs_features = new_op->downcall.resp.features.features;
574		op_release(new_op);
575	} else {
576		orangefs_features = 0;
577	}
578
579	return dget(sb->s_root);
580
581free_sb_and_op:
582	/* Will call orangefs_kill_sb with sb not in list. */
583	ORANGEFS_SB(sb)->no_list = 1;
584	/* ORANGEFS_VFS_OP_FS_UMOUNT is done by orangefs_kill_sb. */
585	deactivate_locked_super(sb);
586free_op:
587	gossip_err("orangefs_mount: mount request failed with %d\n", ret);
588	if (ret == -EINVAL) {
589		gossip_err("Ensure that all orangefs-servers have the same FS configuration files\n");
590		gossip_err("Look at pvfs2-client-core log file (typically /tmp/pvfs2-client.log) for more details\n");
591	}
592
593	op_release(new_op);
594
595	return d;
596}
597
598void orangefs_kill_sb(struct super_block *sb)
599{
600	int r;
601	gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_kill_sb: called\n");
602
603	/* provided sb cleanup */
604	kill_anon_super(sb);
605
606	if (!ORANGEFS_SB(sb)) {
607		mutex_lock(&orangefs_request_mutex);
608		mutex_unlock(&orangefs_request_mutex);
609		return;
610	}
611	/*
612	 * issue the unmount to userspace to tell it to remove the
613	 * dynamic mount info it has for this superblock
614	 */
615	r = orangefs_unmount(ORANGEFS_SB(sb)->id, ORANGEFS_SB(sb)->fs_id,
616	    ORANGEFS_SB(sb)->devname);
617	if (!r)
618		ORANGEFS_SB(sb)->mount_pending = 1;
619
620	if (!ORANGEFS_SB(sb)->no_list) {
621		/* remove the sb from our list of orangefs specific sb's */
622		spin_lock(&orangefs_superblocks_lock);
623		/* not list_del_init */
624		__list_del_entry(&ORANGEFS_SB(sb)->list);
625		ORANGEFS_SB(sb)->list.prev = NULL;
626		spin_unlock(&orangefs_superblocks_lock);
627	}
628
629	/*
630	 * make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us
631	 * gets completed before we free the dang thing.
632	 */
633	mutex_lock(&orangefs_request_mutex);
634	mutex_unlock(&orangefs_request_mutex);
635
636	/* free the orangefs superblock private data */
637	kfree(ORANGEFS_SB(sb));
638}
639
640int orangefs_inode_cache_initialize(void)
641{
642	orangefs_inode_cache = kmem_cache_create_usercopy(
643					"orangefs_inode_cache",
644					sizeof(struct orangefs_inode_s),
645					0,
646					ORANGEFS_CACHE_CREATE_FLAGS,
647					offsetof(struct orangefs_inode_s,
648						link_target),
649					sizeof_field(struct orangefs_inode_s,
650						link_target),
651					orangefs_inode_cache_ctor);
652
653	if (!orangefs_inode_cache) {
654		gossip_err("Cannot create orangefs_inode_cache\n");
655		return -ENOMEM;
656	}
657	return 0;
658}
659
660int orangefs_inode_cache_finalize(void)
661{
662	kmem_cache_destroy(orangefs_inode_cache);
663	return 0;
664}