diff options
Diffstat (limited to 'fs/sysfs')
| -rw-r--r-- | fs/sysfs/dir.c | 37 | ||||
| -rw-r--r-- | fs/sysfs/file.c | 9 | ||||
| -rw-r--r-- | fs/sysfs/inode.c | 9 | ||||
| -rw-r--r-- | fs/sysfs/symlink.c | 6 | ||||
| -rw-r--r-- | fs/sysfs/sysfs.h | 1 | 
5 files changed, 48 insertions, 14 deletions
| diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 49bd219275d..9ee95686444 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -50,6 +50,32 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,  	return sd;  } +/** + * + * Return -EEXIST if there is already a sysfs element with the same name for + * the same parent. + * + * called with parent inode's i_mutex held + */ +int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, +			  const unsigned char *new) +{ +	struct sysfs_dirent * sd; + +	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { +		if (sd->s_element) { +			const unsigned char *existing = sysfs_get_name(sd); +			if (strcmp(existing, new)) +				continue; +			else +				return -EEXIST; +		} +	} + +	return 0; +} + +  int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,  			void * element, umode_t mode, int type)  { @@ -102,7 +128,11 @@ static int create_dir(struct kobject * k, struct dentry * p,  	mutex_lock(&p->d_inode->i_mutex);  	*d = lookup_one_len(n, p, strlen(n));  	if (!IS_ERR(*d)) { -		error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR); + 		if (sysfs_dirent_exist(p->d_fsdata, n)) +  			error = -EEXIST; +  		else +			error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, +								SYSFS_DIR);  		if (!error) {  			error = sysfs_create(*d, mode, init_dir);  			if (!error) { @@ -302,6 +332,7 @@ void sysfs_remove_dir(struct kobject * kobj)  	 * Drop reference from dget() on entrance.  	 */  	dput(dentry); +	kobj->dentry = NULL;  }  int sysfs_rename_dir(struct kobject * kobj, const char *new_name) @@ -479,7 +510,3 @@ struct file_operations sysfs_dir_operations = {  	.read		= generic_read_dir,  	.readdir	= sysfs_readdir,  }; - -EXPORT_SYMBOL_GPL(sysfs_create_dir); -EXPORT_SYMBOL_GPL(sysfs_remove_dir); -EXPORT_SYMBOL_GPL(sysfs_rename_dir); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d0e3d849516..5e83e724678 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -301,9 +301,8 @@ static int check_perm(struct inode * inode, struct file * file)  	/* No error? Great, allocate a buffer for the file, and store it  	 * it in file->private_data for easy access.  	 */ -	buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL); +	buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);  	if (buffer) { -		memset(buffer,0,sizeof(struct sysfs_buffer));  		init_MUTEX(&buffer->sem);  		buffer->needs_read_fill = 1;  		buffer->ops = ops; @@ -362,10 +361,12 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)  {  	struct sysfs_dirent * parent_sd = dir->d_fsdata;  	umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; -	int error = 0; +	int error = -EEXIST;  	mutex_lock(&dir->d_inode->i_mutex); -	error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type); +	if (!sysfs_dirent_exist(parent_sd, attr->name)) +		error = sysfs_make_dirent(parent_sd, NULL, (void *)attr, +					  mode, type);  	mutex_unlock(&dir->d_inode->i_mutex);  	return error; diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 689f7bcfaf3..4c29ac41ac3 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -54,11 +54,10 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)  	if (!sd_iattr) {  		/* setting attributes for the first time, allocate now */ -		sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL); +		sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);  		if (!sd_iattr)  			return -ENOMEM;  		/* assign default attributes */ -		memset(sd_iattr, 0, sizeof(struct iattr));  		sd_iattr->ia_mode = sd->s_mode;  		sd_iattr->ia_uid = 0;  		sd_iattr->ia_gid = 0; @@ -227,12 +226,16 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)  void sysfs_hash_and_remove(struct dentry * dir, const char * name)  {  	struct sysfs_dirent * sd; -	struct sysfs_dirent * parent_sd = dir->d_fsdata; +	struct sysfs_dirent * parent_sd; + +	if (!dir) +		return;  	if (dir->d_inode == NULL)  		/* no inode means this hasn't been made visible yet */  		return; +	parent_sd = dir->d_fsdata;  	mutex_lock(&dir->d_inode->i_mutex);  	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {  		if (!sd->s_element) diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index e38d6338a20..d2eac3ceed5 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -66,6 +66,7 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj  	if (!error)  		return 0; +	kobject_put(target);  	kfree(sl->link_name);  exit2:  	kfree(sl); @@ -82,12 +83,13 @@ exit1:  int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name)  {  	struct dentry * dentry = kobj->dentry; -	int error = 0; +	int error = -EEXIST;  	BUG_ON(!kobj || !kobj->dentry || !name);  	mutex_lock(&dentry->d_inode->i_mutex); -	error = sysfs_add_link(dentry, name, target); +	if (!sysfs_dirent_exist(dentry->d_fsdata, name)) +		error = sysfs_add_link(dentry, name, target);  	mutex_unlock(&dentry->d_inode->i_mutex);  	return error;  } diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3f8953e0e5d..cf11d5b789d 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -5,6 +5,7 @@ extern kmem_cache_t *sysfs_dir_cachep;  extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);  extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); +extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *);  extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,  				umode_t, int); | 
