Linux Audio

Check our new training course

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