Commit 0f423895 authored by James Bottomley's avatar James Bottomley
Browse files

[SCSI] sysfs: make group is_valid return a mode_t



We have a problem in scsi_transport_spi in that we need to customise
not only the visibility of the attributes, but also their mode.  Fix
this by making the is_visible() callback return a mode, with 0
indicating is not visible.

Also add a sysfs_update_group() API to allow us to change either the
visibility or mode of the files at any time on the fly.

Acked-by: default avatarKay Sievers <kay.sievers@vrfy.org>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent bbd1ae41
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -477,11 +477,10 @@ const struct file_operations sysfs_file_operations = {
	.poll		= sysfs_poll,
};


int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
		   int type)
int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
			const struct attribute *attr, int type, mode_t amode)
{
	umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
	umode_t mode = (amode & S_IALLUGO) | S_IFREG;
	struct sysfs_addrm_cxt acxt;
	struct sysfs_dirent *sd;
	int rc;
@@ -502,6 +501,13 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
}


int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
		   int type)
{
	return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
}


/**
 *	sysfs_create_file - create an attribute file for an object.
 *	@kobj:	object we're creating for. 
+70 −13
Original line number Diff line number Diff line
@@ -23,35 +23,50 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
	int i;

	for (i = 0, attr = grp->attrs; *attr; i++, attr++)
		if (!grp->is_visible ||
		    grp->is_visible(kobj, *attr, i))
		sysfs_hash_and_remove(dir_sd, (*attr)->name);
}

static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
			const struct attribute_group *grp)
			const struct attribute_group *grp, int update)
{
	struct attribute *const* attr;
	int error = 0, i;

	for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++)
		if (!grp->is_visible ||
		    grp->is_visible(kobj, *attr, i))
			error |=
				sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
	for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) {
		mode_t mode = 0;

		/* in update mode, we're changing the permissions or
		 * visibility.  Do this by first removing then
		 * re-adding (if required) the file */
		if (update)
			sysfs_hash_and_remove(dir_sd, (*attr)->name);
		if (grp->is_visible) {
			mode = grp->is_visible(kobj, *attr, i);
			if (!mode)
				continue;
		}
		error = sysfs_add_file_mode(dir_sd, *attr, SYSFS_KOBJ_ATTR,
					    (*attr)->mode | mode);
		if (unlikely(error))
			break;
	}
	if (error)
		remove_files(dir_sd, kobj, grp);
	return error;
}


int sysfs_create_group(struct kobject * kobj, 
static int internal_create_group(struct kobject *kobj, int update,
				 const struct attribute_group *grp)
{
	struct sysfs_dirent *sd;
	int error;

	BUG_ON(!kobj || !kobj->sd);
	BUG_ON(!kobj || (!update && !kobj->sd));

	/* Updates may happen before the object has been instantiated */
	if (unlikely(update && !kobj->sd))
		return -EINVAL;

	if (grp->name) {
		error = sysfs_create_subdir(kobj, grp->name, &sd);
@@ -60,7 +75,7 @@ int sysfs_create_group(struct kobject * kobj,
	} else
		sd = kobj->sd;
	sysfs_get(sd);
	error = create_files(sd, kobj, grp);
	error = create_files(sd, kobj, grp, update);
	if (error) {
		if (grp->name)
			sysfs_remove_subdir(sd);
@@ -69,6 +84,47 @@ int sysfs_create_group(struct kobject * kobj,
	return error;
}

/**
 * sysfs_create_group - given a directory kobject, create an attribute group
 * @kobj:	The kobject to create the group on
 * @grp:	The attribute group to create
 *
 * This function creates a group for the first time.  It will explicitly
 * warn and error if any of the attribute files being created already exist.
 *
 * Returns 0 on success or error.
 */
int sysfs_create_group(struct kobject *kobj,
		       const struct attribute_group *grp)
{
	return internal_create_group(kobj, 0, grp);
}

/**
 * sysfs_update_group - given a directory kobject, create an attribute group
 * @kobj:	The kobject to create the group on
 * @grp:	The attribute group to create
 *
 * This function updates an attribute group.  Unlike
 * sysfs_create_group(), it will explicitly not warn or error if any
 * of the attribute files being created already exist.  Furthermore,
 * if the visibility of the files has changed through the is_visible()
 * callback, it will update the permissions and add or remove the
 * relevant files.
 *
 * The primary use for this function is to call it after making a change
 * that affects group visibility.
 *
 * Returns 0 on success or error.
 */
int sysfs_update_group(struct kobject *kobj,
		       const struct attribute_group *grp)
{
	return internal_create_group(kobj, 1, grp);
}



void sysfs_remove_group(struct kobject * kobj, 
			const struct attribute_group * grp)
{
@@ -95,4 +151,5 @@ void sysfs_remove_group(struct kobject * kobj,


EXPORT_SYMBOL_GPL(sysfs_create_group);
EXPORT_SYMBOL_GPL(sysfs_update_group);
EXPORT_SYMBOL_GPL(sysfs_remove_group);
+2 −0
Original line number Diff line number Diff line
@@ -154,6 +154,8 @@ extern const struct file_operations sysfs_file_operations;
int sysfs_add_file(struct sysfs_dirent *dir_sd,
		   const struct attribute *attr, int type);

int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
			const struct attribute *attr, int type, mode_t amode);
/*
 * bin.c
 */
+3 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ struct attribute {

struct attribute_group {
	const char		*name;
	int			(*is_visible)(struct kobject *,
	mode_t			(*is_visible)(struct kobject *,
					      struct attribute *, int);
	struct attribute	**attrs;
};
@@ -105,6 +105,8 @@ void sysfs_remove_link(struct kobject *kobj, const char *name);

int __must_check sysfs_create_group(struct kobject *kobj,
				    const struct attribute_group *grp);
int sysfs_update_group(struct kobject *kobj,
		       const struct attribute_group *grp);
void sysfs_remove_group(struct kobject *kobj,
			const struct attribute_group *grp);
int sysfs_add_file_to_group(struct kobject *kobj,