Skip to content

Commit

Permalink
sysfs: Gut sysfs_addrm_start and sysfs_addrm_finish
Browse files Browse the repository at this point in the history
With lazy inode updates and dentry operations bringing everything
into sync on demand there is no longer any need to immediately
update the vfs or grab i_mutex to protect those updates as we
make changes to sysfs.

Acked-by: Serge Hallyn <serue@us.ibm.com>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Eric W. Biederman authored and Greg Kroah-Hartman committed Dec 11, 2009
1 parent 06fc0d6 commit a16bbc3
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 89 deletions.
91 changes: 4 additions & 87 deletions fs/sysfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,60 +386,27 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
return NULL;
}

static int sysfs_ilookup_test(struct inode *inode, void *arg)
{
struct sysfs_dirent *sd = arg;
return inode->i_ino == sd->s_ino;
}

/**
* sysfs_addrm_start - prepare for sysfs_dirent add/remove
* @acxt: pointer to sysfs_addrm_cxt to be used
* @parent_sd: parent sysfs_dirent
*
* This function is called when the caller is about to add or
* remove sysfs_dirent under @parent_sd. This function acquires
* sysfs_mutex, grabs inode for @parent_sd if available and lock
* i_mutex of it. @acxt is used to keep and pass context to
* sysfs_mutex. @acxt is used to keep and pass context to
* other addrm functions.
*
* LOCKING:
* Kernel thread context (may sleep). sysfs_mutex is locked on
* return. i_mutex of parent inode is locked on return if
* available.
* return.
*/
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
struct sysfs_dirent *parent_sd)
{
struct inode *inode;

memset(acxt, 0, sizeof(*acxt));
acxt->parent_sd = parent_sd;

/* Lookup parent inode. inode initialization is protected by
* sysfs_mutex, so inode existence can be determined by
* looking up inode while holding sysfs_mutex.
*/
mutex_lock(&sysfs_mutex);

inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
parent_sd);
if (inode) {
WARN_ON(inode->i_state & I_NEW);

/* parent inode available */
acxt->parent_inode = inode;

/* sysfs_mutex is below i_mutex in lock hierarchy.
* First, trylock i_mutex. If fails, unlock
* sysfs_mutex and lock them in order.
*/
if (!mutex_trylock(&inode->i_mutex)) {
mutex_unlock(&sysfs_mutex);
mutex_lock(&inode->i_mutex);
mutex_lock(&sysfs_mutex);
}
}
}

/**
Expand Down Expand Up @@ -471,11 +438,6 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)

sd->s_parent = sysfs_get(acxt->parent_sd);

if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
inc_nlink(acxt->parent_inode);

acxt->cnt++;

sysfs_link_sibling(sd);

/* Update timestamps on the parent */
Expand Down Expand Up @@ -579,40 +541,6 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
sd->s_flags |= SYSFS_FLAG_REMOVED;
sd->s_sibling = acxt->removed;
acxt->removed = sd;

if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
drop_nlink(acxt->parent_inode);

acxt->cnt++;
}

/**
* sysfs_dec_nlink - Decrement link count for the specified sysfs_dirent
* @sd: target sysfs_dirent
*
* Decrement nlink for @sd. @sd must have been unlinked from its
* parent on entry to this function such that it can't be looked
* up anymore.
*/
static void sysfs_dec_nlink(struct sysfs_dirent *sd)
{
struct inode *inode;

inode = ilookup(sysfs_sb, sd->s_ino);
if (!inode)
return;

/* adjust nlink and update timestamp */
mutex_lock(&inode->i_mutex);

inode->i_ctime = CURRENT_TIME;
drop_nlink(inode);
if (sysfs_type(sd) == SYSFS_DIR)
drop_nlink(inode);

mutex_unlock(&inode->i_mutex);

iput(inode);
}

/**
Expand All @@ -621,25 +549,15 @@ static void sysfs_dec_nlink(struct sysfs_dirent *sd)
*
* Finish up sysfs_dirent add/remove. Resources acquired by
* sysfs_addrm_start() are released and removed sysfs_dirents are
* cleaned up. Timestamps on the parent inode are updated.
* cleaned up.
*
* LOCKING:
* All mutexes acquired by sysfs_addrm_start() are released.
* sysfs_mutex is released.
*/
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
{
/* release resources acquired by sysfs_addrm_start() */
mutex_unlock(&sysfs_mutex);
if (acxt->parent_inode) {
struct inode *inode = acxt->parent_inode;

/* if added/removed, update timestamps on the parent */
if (acxt->cnt)
inode->i_ctime = inode->i_mtime = CURRENT_TIME;

mutex_unlock(&inode->i_mutex);
iput(inode);
}

/* kill removed sysfs_dirents */
while (acxt->removed) {
Expand All @@ -648,7 +566,6 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
acxt->removed = sd->s_sibling;
sd->s_sibling = NULL;

sysfs_dec_nlink(sd);
sysfs_deactivate(sd);
unmap_bin_file(sd);
sysfs_put(sd);
Expand Down
2 changes: 0 additions & 2 deletions fs/sysfs/sysfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
*/
struct sysfs_addrm_cxt {
struct sysfs_dirent *parent_sd;
struct inode *parent_inode;
struct sysfs_dirent *removed;
int cnt;
};

/*
Expand Down

0 comments on commit a16bbc3

Please sign in to comment.