Skip to content

Commit

Permalink
sysfs: Fix locking and factor out sysfs_sd_setattr
Browse files Browse the repository at this point in the history
Cleanly separate the work that is specific to setting the
attributes of a sysfs_dirent from what is needed to update
the attributes of a vfs inode.

Additionally grab the sysfs_mutex to keep any nasties from
surprising us when updating the sysfs_dirent.

Acked-by: Tejun Heo <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
ebiederm authored and gregkh committed Dec 11, 2009
1 parent 4be3df2 commit 35df63c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 20 deletions.
51 changes: 31 additions & 20 deletions fs/sysfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,30 +65,14 @@ static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd)
return attrs;
}

int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr)
{
struct inode * inode = dentry->d_inode;
struct sysfs_dirent * sd = dentry->d_fsdata;
struct sysfs_inode_attrs *sd_attrs;
struct iattr *iattrs;
unsigned int ia_valid = iattr->ia_valid;
int error;

if (!sd)
return -EINVAL;

sd_attrs = sd->s_iattr;

error = inode_change_ok(inode, iattr);
if (error)
return error;

iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */

error = inode_setattr(inode, iattr);
if (error)
return error;

if (!sd_attrs) {
/* setting attributes for the first time, allocate now */
sd_attrs = sysfs_init_inode_attrs(sd);
Expand All @@ -111,12 +95,39 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
iattrs->ia_ctime = iattr->ia_ctime;
if (ia_valid & ATTR_MODE) {
umode_t mode = iattr->ia_mode;

if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
mode &= ~S_ISGID;
iattrs->ia_mode = sd->s_mode = mode;
}
}
return 0;
}

int sysfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
struct inode *inode = dentry->d_inode;
struct sysfs_dirent *sd = dentry->d_fsdata;
int error;

if (!sd)
return -EINVAL;

error = inode_change_ok(inode, iattr);
if (error)
return error;

iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */
if (iattr->ia_valid & ATTR_MODE) {
if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
iattr->ia_mode &= ~S_ISGID;
}

error = inode_setattr(inode, iattr);
if (error)
return error;

mutex_lock(&sysfs_mutex);
error = sysfs_sd_setattr(sd, iattr);
mutex_unlock(&sysfs_mutex);

return error;
}

Expand Down
1 change: 1 addition & 0 deletions fs/sysfs/sysfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)
*/
struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
void sysfs_delete_inode(struct inode *inode);
int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr);
int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags);
Expand Down

0 comments on commit 35df63c

Please sign in to comment.