Linux Audio

Check our new training course

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