Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  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}