示例#1
0
文件: proc.c 项目: AlexShiLucky/linux
/*
 * handle writes to /proc/fs/afs/cells
 * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
 */
static int afs_proc_cells_write(struct file *file, char *buf, size_t size)
{
	struct seq_file *m = file->private_data;
	struct afs_net *net = afs_seq2net(m);
	char *name, *args;
	int ret;

	/* trim to first NL */
	name = memchr(buf, '\n', size);
	if (name)
		*name = 0;

	/* split into command, name and argslist */
	name = strchr(buf, ' ');
	if (!name)
		goto inval;
	do {
		*name++ = 0;
	} while(*name == ' ');
	if (!*name)
		goto inval;

	args = strchr(name, ' ');
	if (args) {
		do {
			*args++ = 0;
		} while(*args == ' ');
		if (!*args)
			goto inval;
	}

	/* determine command to perform */
	_debug("cmd=%s name=%s args=%s", buf, name, args);

	if (strcmp(buf, "add") == 0) {
		struct afs_cell *cell;

		cell = afs_lookup_cell(net, name, strlen(name), args, true);
		if (IS_ERR(cell)) {
			ret = PTR_ERR(cell);
			goto done;
		}

		if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags))
			afs_put_cell(net, cell);
	} else {
		goto inval;
	}

	ret = 0;

done:
	_leave(" = %d", ret);
	return ret;

inval:
	ret = -EINVAL;
	printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
	goto done;
}
示例#2
0
文件: super.c 项目: Anjali05/linux
static void afs_destroy_sbi(struct afs_super_info *as)
{
	if (as) {
		afs_put_volume(as->cell, as->volume);
		afs_put_cell(afs_net(as->net_ns), as->cell);
		put_net(as->net_ns);
		kfree(as);
	}
}
示例#3
0
/*
 * parse the mount options
 * - this function has been shamelessly adapted from the ext3 fs which
 *   shamelessly adapted it from the msdos fs
 */
static int afs_parse_options(struct afs_mount_params *params,
			     char *options, const char **devname)
{
	struct afs_cell *cell;
	substring_t args[MAX_OPT_ARGS];
	char *p;
	int token;

	_enter("%s", options);

	options[PAGE_SIZE - 1] = 0;

	while ((p = strsep(&options, ","))) {
		if (!*p)
			continue;

		token = match_token(p, afs_options_list, args);
		switch (token) {
		case afs_opt_cell:
			rcu_read_lock();
			cell = afs_lookup_cell_rcu(params->net,
						   args[0].from,
						   args[0].to - args[0].from);
			rcu_read_unlock();
			if (IS_ERR(cell))
				return PTR_ERR(cell);
			afs_put_cell(params->net, params->cell);
			params->cell = cell;
			break;

		case afs_opt_rwpath:
			params->rwpath = true;
			break;

		case afs_opt_vol:
			*devname = args[0].from;
			break;

		case afs_opt_autocell:
			params->autocell = true;
			break;

		case afs_opt_dyn:
			params->dyn_root = true;
			break;

		default:
			printk(KERN_ERR "kAFS:"
			       " Unknown or invalid mount option: '%s'\n", p);
			return -EINVAL;
		}
	}

	_leave(" = 0");
	return 0;
}
示例#4
0
文件: super.c 项目: Anjali05/linux
static void afs_free_fc(struct fs_context *fc)
{
	struct afs_fs_context *ctx = fc->fs_private;

	afs_destroy_sbi(fc->s_fs_info);
	afs_put_volume(ctx->cell, ctx->volume);
	afs_put_cell(ctx->net, ctx->cell);
	key_put(ctx->key);
	kfree(ctx);
}
示例#5
0
文件: cell.c 项目: AlexShiLucky/linux
/*
 * set the root cell information
 * - can be called with a module parameter string
 * - can be called from a write to /proc/fs/afs/rootcell
 */
int afs_cell_init(struct afs_net *net, const char *rootcell)
{
	struct afs_cell *old_root, *new_root;
	const char *cp, *vllist;
	size_t len;

	_enter("");

	if (!rootcell) {
		/* module is loaded with no parameters, or built statically.
		 * - in the future we might initialize cell DB here.
		 */
		_leave(" = 0 [no root]");
		return 0;
	}

	cp = strchr(rootcell, ':');
	if (!cp) {
		_debug("kAFS: no VL server IP addresses specified");
		vllist = NULL;
		len = strlen(rootcell);
	} else {
		vllist = cp + 1;
		len = cp - rootcell;
	}

	/* allocate a cell record for the root cell */
	new_root = afs_lookup_cell(net, rootcell, len, vllist, false);
	if (IS_ERR(new_root)) {
		_leave(" = %ld", PTR_ERR(new_root));
		return PTR_ERR(new_root);
	}

	if (!test_and_set_bit(AFS_CELL_FL_NO_GC, &new_root->flags))
		afs_get_cell(new_root);

	/* install the new cell */
	write_seqlock(&net->cells_lock);
	old_root = rcu_access_pointer(net->ws_cell);
	rcu_assign_pointer(net->ws_cell, new_root);
	write_sequnlock(&net->cells_lock);

	afs_put_cell(net, old_root);
	_leave(" = 0");
	return 0;
}
示例#6
0
文件: cell.c 项目: AlexShiLucky/linux
/*
 * Purge in-memory cell database.
 */
void afs_cell_purge(struct afs_net *net)
{
	struct afs_cell *ws;

	_enter("");

	write_seqlock(&net->cells_lock);
	ws = rcu_access_pointer(net->ws_cell);
	RCU_INIT_POINTER(net->ws_cell, NULL);
	write_sequnlock(&net->cells_lock);
	afs_put_cell(net, ws);

	_debug("del timer");
	if (del_timer_sync(&net->cells_timer))
		atomic_dec(&net->cells_outstanding);

	_debug("kick mgr");
	afs_queue_cell_manager(net);

	_debug("wait");
	wait_var_event(&net->cells_outstanding,
		       !atomic_read(&net->cells_outstanding));
	_leave("");
}
示例#7
0
文件: super.c 项目: Anjali05/linux
/*
 * Parse the source name to get cell name, volume name, volume type and R/W
 * selector.
 *
 * This can be one of the following:
 *	"%[cell:]volume[.]"		R/W volume
 *	"#[cell:]volume[.]"		R/O or R/W volume (R/O parent),
 *					 or R/W (R/W parent) volume
 *	"%[cell:]volume.readonly"	R/O volume
 *	"#[cell:]volume.readonly"	R/O volume
 *	"%[cell:]volume.backup"		Backup volume
 *	"#[cell:]volume.backup"		Backup volume
 */
static int afs_parse_source(struct fs_context *fc, struct fs_parameter *param)
{
	struct afs_fs_context *ctx = fc->fs_private;
	struct afs_cell *cell;
	const char *cellname, *suffix, *name = param->string;
	int cellnamesz;

	_enter(",%s", name);

	if (!name) {
		printk(KERN_ERR "kAFS: no volume name specified\n");
		return -EINVAL;
	}

	if ((name[0] != '%' && name[0] != '#') || !name[1]) {
		/* To use dynroot, we don't want to have to provide a source */
		if (strcmp(name, "none") == 0) {
			ctx->no_cell = true;
			return 0;
		}
		printk(KERN_ERR "kAFS: unparsable volume name\n");
		return -EINVAL;
	}

	/* determine the type of volume we're looking for */
	if (name[0] == '%') {
		ctx->type = AFSVL_RWVOL;
		ctx->force = true;
	}
	name++;

	/* split the cell name out if there is one */
	ctx->volname = strchr(name, ':');
	if (ctx->volname) {
		cellname = name;
		cellnamesz = ctx->volname - name;
		ctx->volname++;
	} else {
		ctx->volname = name;
		cellname = NULL;
		cellnamesz = 0;
	}

	/* the volume type is further affected by a possible suffix */
	suffix = strrchr(ctx->volname, '.');
	if (suffix) {
		if (strcmp(suffix, ".readonly") == 0) {
			ctx->type = AFSVL_ROVOL;
			ctx->force = true;
		} else if (strcmp(suffix, ".backup") == 0) {
			ctx->type = AFSVL_BACKVOL;
			ctx->force = true;
		} else if (suffix[1] == 0) {
		} else {
			suffix = NULL;
		}
	}

	ctx->volnamesz = suffix ?
		suffix - ctx->volname : strlen(ctx->volname);

	_debug("cell %*.*s [%p]",
	       cellnamesz, cellnamesz, cellname ?: "", ctx->cell);

	/* lookup the cell record */
	if (cellname) {
		cell = afs_lookup_cell(ctx->net, cellname, cellnamesz,
				       NULL, false);
		if (IS_ERR(cell)) {
			pr_err("kAFS: unable to lookup cell '%*.*s'\n",
			       cellnamesz, cellnamesz, cellname ?: "");
			return PTR_ERR(cell);
		}
		afs_put_cell(ctx->net, ctx->cell);
		ctx->cell = cell;
	}

	_debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
	       ctx->cell->name, ctx->cell,
	       ctx->volnamesz, ctx->volnamesz, ctx->volname,
	       suffix ?: "-", ctx->type, ctx->force ? " FORCE" : "");

	fc->source = param->string;
	param->string = NULL;
	return 0;
}
示例#8
0
/*
 * parse a device name to get cell name, volume name, volume type and R/W
 * selector
 * - this can be one of the following:
 *	"%[cell:]volume[.]"		R/W volume
 *	"#[cell:]volume[.]"		R/O or R/W volume (rwpath=0),
 *					 or R/W (rwpath=1) volume
 *	"%[cell:]volume.readonly"	R/O volume
 *	"#[cell:]volume.readonly"	R/O volume
 *	"%[cell:]volume.backup"		Backup volume
 *	"#[cell:]volume.backup"		Backup volume
 */
static int afs_parse_device_name(struct afs_mount_params *params,
				 const char *name)
{
	struct afs_cell *cell;
	const char *cellname, *suffix;
	int cellnamesz;

	_enter(",%s", name);

	if (!name) {
		printk(KERN_ERR "kAFS: no volume name specified\n");
		return -EINVAL;
	}

	if ((name[0] != '%' && name[0] != '#') || !name[1]) {
		printk(KERN_ERR "kAFS: unparsable volume name\n");
		return -EINVAL;
	}

	/* determine the type of volume we're looking for */
	params->type = AFSVL_ROVOL;
	params->force = false;
	if (params->rwpath || name[0] == '%') {
		params->type = AFSVL_RWVOL;
		params->force = true;
	}
	name++;

	/* split the cell name out if there is one */
	params->volname = strchr(name, ':');
	if (params->volname) {
		cellname = name;
		cellnamesz = params->volname - name;
		params->volname++;
	} else {
		params->volname = name;
		cellname = NULL;
		cellnamesz = 0;
	}

	/* the volume type is further affected by a possible suffix */
	suffix = strrchr(params->volname, '.');
	if (suffix) {
		if (strcmp(suffix, ".readonly") == 0) {
			params->type = AFSVL_ROVOL;
			params->force = true;
		} else if (strcmp(suffix, ".backup") == 0) {
			params->type = AFSVL_BACKVOL;
			params->force = true;
		} else if (suffix[1] == 0) {
		} else {
			suffix = NULL;
		}
	}

	params->volnamesz = suffix ?
		suffix - params->volname : strlen(params->volname);

	_debug("cell %*.*s [%p]",
	       cellnamesz, cellnamesz, cellname ?: "", params->cell);

	/* lookup the cell record */
	if (cellname || !params->cell) {
		cell = afs_cell_lookup(cellname, cellnamesz, true);
		if (IS_ERR(cell)) {
			printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n",
			       cellnamesz, cellnamesz, cellname ?: "");
			return PTR_ERR(cell);
		}
		afs_put_cell(params->cell);
		params->cell = cell;
	}
示例#9
0
文件: cell.c 项目: AlexShiLucky/linux
/*
 * Look up and get an activation reference on a cell record under RCU
 * conditions.  The caller must hold the RCU read lock.
 */
struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
				     const char *name, unsigned int namesz)
{
	struct afs_cell *cell = NULL;
	struct rb_node *p;
	int n, seq = 0, ret = 0;

	_enter("%*.*s", namesz, namesz, name);

	if (name && namesz == 0)
		return ERR_PTR(-EINVAL);
	if (namesz > AFS_MAXCELLNAME)
		return ERR_PTR(-ENAMETOOLONG);

	do {
		/* Unfortunately, rbtree walking doesn't give reliable results
		 * under just the RCU read lock, so we have to check for
		 * changes.
		 */
		if (cell)
			afs_put_cell(net, cell);
		cell = NULL;
		ret = -ENOENT;

		read_seqbegin_or_lock(&net->cells_lock, &seq);

		if (!name) {
			cell = rcu_dereference_raw(net->ws_cell);
			if (cell) {
				afs_get_cell(cell);
				break;
			}
			ret = -EDESTADDRREQ;
			continue;
		}

		p = rcu_dereference_raw(net->cells.rb_node);
		while (p) {
			cell = rb_entry(p, struct afs_cell, net_node);

			n = strncasecmp(cell->name, name,
					min_t(size_t, cell->name_len, namesz));
			if (n == 0)
				n = cell->name_len - namesz;
			if (n < 0) {
				p = rcu_dereference_raw(p->rb_left);
			} else if (n > 0) {
				p = rcu_dereference_raw(p->rb_right);
			} else {
				if (atomic_inc_not_zero(&cell->usage)) {
					ret = 0;
					break;
				}
				/* We want to repeat the search, this time with
				 * the lock properly locked.
				 */
			}
			cell = NULL;
		}

	} while (need_seqretry(&net->cells_lock, seq));

	done_seqretry(&net->cells_lock, seq);

	return ret == 0 ? cell : ERR_PTR(ret);
}
示例#10
0
文件: cell.c 项目: AlexShiLucky/linux
/*
 * afs_lookup_cell - Look up or create a cell record.
 * @net:	The network namespace
 * @name:	The name of the cell.
 * @namesz:	The strlen of the cell name.
 * @vllist:	A colon/comma separated list of numeric IP addresses or NULL.
 * @excl:	T if an error should be given if the cell name already exists.
 *
 * Look up a cell record by name and query the DNS for VL server addresses if
 * needed.  Note that that actual DNS query is punted off to the manager thread
 * so that this function can return immediately if interrupted whilst allowing
 * cell records to be shared even if not yet fully constructed.
 */
struct afs_cell *afs_lookup_cell(struct afs_net *net,
				 const char *name, unsigned int namesz,
				 const char *vllist, bool excl)
{
	struct afs_cell *cell, *candidate, *cursor;
	struct rb_node *parent, **pp;
	int ret, n;

	_enter("%s,%s", name, vllist);

	if (!excl) {
		rcu_read_lock();
		cell = afs_lookup_cell_rcu(net, name, namesz);
		rcu_read_unlock();
		if (!IS_ERR(cell))
			goto wait_for_cell;
	}

	/* Assume we're probably going to create a cell and preallocate and
	 * mostly set up a candidate record.  We can then use this to stash the
	 * name, the net namespace and VL server addresses.
	 *
	 * We also want to do this before we hold any locks as it may involve
	 * upcalling to userspace to make DNS queries.
	 */
	candidate = afs_alloc_cell(net, name, namesz, vllist);
	if (IS_ERR(candidate)) {
		_leave(" = %ld", PTR_ERR(candidate));
		return candidate;
	}

	/* Find the insertion point and check to see if someone else added a
	 * cell whilst we were allocating.
	 */
	write_seqlock(&net->cells_lock);

	pp = &net->cells.rb_node;
	parent = NULL;
	while (*pp) {
		parent = *pp;
		cursor = rb_entry(parent, struct afs_cell, net_node);

		n = strncasecmp(cursor->name, name,
				min_t(size_t, cursor->name_len, namesz));
		if (n == 0)
			n = cursor->name_len - namesz;
		if (n < 0)
			pp = &(*pp)->rb_left;
		else if (n > 0)
			pp = &(*pp)->rb_right;
		else
			goto cell_already_exists;
	}

	cell = candidate;
	candidate = NULL;
	rb_link_node_rcu(&cell->net_node, parent, pp);
	rb_insert_color(&cell->net_node, &net->cells);
	atomic_inc(&net->cells_outstanding);
	write_sequnlock(&net->cells_lock);

	queue_work(afs_wq, &cell->manager);

wait_for_cell:
	_debug("wait_for_cell");
	ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NOT_READY, TASK_INTERRUPTIBLE);
	smp_rmb();

	switch (READ_ONCE(cell->state)) {
	case AFS_CELL_FAILED:
		ret = cell->error;
		goto error;
	default:
		_debug("weird %u %d", cell->state, cell->error);
		goto error;
	case AFS_CELL_ACTIVE:
		break;
	}

	_leave(" = %p [cell]", cell);
	return cell;

cell_already_exists:
	_debug("cell exists");
	cell = cursor;
	if (excl) {
		ret = -EEXIST;
	} else {
		afs_get_cell(cursor);
		ret = 0;
	}
	write_sequnlock(&net->cells_lock);
	kfree(candidate);
	if (ret == 0)
		goto wait_for_cell;
	goto error_noput;
error:
	afs_put_cell(net, cell);
error_noput:
	_leave(" = %d [error]", ret);
	return ERR_PTR(ret);
}