aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/fid.c17
-rw-r--r--fs/9p/fid.h1
-rw-r--r--fs/autofs4/root.c31
-rw-r--r--fs/cifs/CHANGES5
-rw-r--r--fs/cifs/README13
-rw-r--r--fs/cifs/TODO3
-rw-r--r--fs/cifs/file.c33
-rw-r--r--fs/cifs/sess.c4
-rw-r--r--fs/direct-io.c18
-rw-r--r--fs/ecryptfs/inode.c4
-rw-r--r--fs/exec.c25
-rw-r--r--fs/jffs2/write.c3
-rw-r--r--fs/proc/array.c44
-rw-r--r--fs/signalfd.c14
-rw-r--r--fs/sysfs/bin.c7
-rw-r--r--fs/sysfs/dir.c21
16 files changed, 133 insertions, 110 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 08fa320b7e6..15e05a15b57 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -92,23 +92,6 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
return fid;
}
-struct p9_fid *v9fs_fid_lookup_remove(struct dentry *dentry)
-{
- struct p9_fid *fid;
- struct v9fs_dentry *dent;
-
- dent = dentry->d_fsdata;
- fid = v9fs_fid_lookup(dentry);
- if (!IS_ERR(fid)) {
- spin_lock(&dent->lock);
- list_del(&fid->dlist);
- spin_unlock(&dent->lock);
- }
-
- return fid;
-}
-
-
/**
* v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and
* release it
diff --git a/fs/9p/fid.h b/fs/9p/fid.h
index 47a0ba74287..26e07df783b 100644
--- a/fs/9p/fid.h
+++ b/fs/9p/fid.h
@@ -28,6 +28,5 @@ struct v9fs_dentry {
};
struct p9_fid *v9fs_fid_lookup(struct dentry *dentry);
-struct p9_fid *v9fs_fid_lookup_remove(struct dentry *dentry);
struct p9_fid *v9fs_fid_clone(struct dentry *dentry);
int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 2d4c8a3e604..45ff3d63b75 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -587,19 +587,20 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
unhashed = autofs4_lookup_unhashed(sbi, dentry->d_parent, &dentry->d_name);
if (!unhashed) {
/*
- * Mark the dentry incomplete, but add it. This is needed so
- * that the VFS layer knows about the dentry, and we can count
- * on catching any lookups through the revalidate.
- *
- * Let all the hard work be done by the revalidate function that
- * needs to be able to do this anyway..
- *
- * We need to do this before we release the directory semaphore.
+ * Mark the dentry incomplete but don't hash it. We do this
+ * to serialize our inode creation operations (symlink and
+ * mkdir) which prevents deadlock during the callback to
+ * the daemon. Subsequent user space lookups for the same
+ * dentry are placed on the wait queue while the daemon
+ * itself is allowed passage unresticted so the create
+ * operation itself can then hash the dentry. Finally,
+ * we check for the hashed dentry and return the newly
+ * hashed dentry.
*/
dentry->d_op = &autofs4_root_dentry_operations;
dentry->d_fsdata = NULL;
- d_add(dentry, NULL);
+ d_instantiate(dentry, NULL);
} else {
struct autofs_info *ino = autofs4_dentry_ino(unhashed);
DPRINTK("rehash %p with %p", dentry, unhashed);
@@ -607,15 +608,17 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
* If we are racing with expire the request might not
* be quite complete but the directory has been removed
* so it must have been successful, so just wait for it.
+ * We need to ensure the AUTOFS_INF_EXPIRING flag is clear
+ * before continuing as revalidate may fail when calling
+ * try_to_fill_dentry (returning EAGAIN) if we don't.
*/
- if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
+ while (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
DPRINTK("wait for incomplete expire %p name=%.*s",
unhashed, unhashed->d_name.len,
unhashed->d_name.name);
autofs4_wait(sbi, unhashed, NFY_NONE);
DPRINTK("request completed");
}
- d_rehash(unhashed);
dentry = unhashed;
}
@@ -658,7 +661,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
* for all system calls, but it should be OK for the operations
* we permit from an autofs.
*/
- if (dentry->d_inode && d_unhashed(dentry)) {
+ if (!oz_mode && d_unhashed(dentry)) {
/*
* A user space application can (and has done in the past)
* remove and re-create this directory during the callback.
@@ -716,7 +719,7 @@ static int autofs4_dir_symlink(struct inode *dir,
strcpy(cp, symname);
inode = autofs4_get_inode(dir->i_sb, ino);
- d_instantiate(dentry, inode);
+ d_add(dentry, inode);
if (dir == dir->i_sb->s_root->d_inode)
dentry->d_op = &autofs4_root_dentry_operations;
@@ -844,7 +847,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
return -ENOSPC;
inode = autofs4_get_inode(dir->i_sb, ino);
- d_instantiate(dentry, inode);
+ d_add(dentry, inode);
if (dir == dir->i_sb->s_root->d_inode)
dentry->d_op = &autofs4_root_dentry_operations;
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 6d84ca2beea..bed6215c079 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -3,7 +3,10 @@ Version 1.50
Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is
done with "serverino" mount option). Add support for POSIX Unlink
(helps with certain sharing violation cases when server such as
-Samba supports newer POSIX CIFS Protocol Extensions).
+Samba supports newer POSIX CIFS Protocol Extensions). Add "nounix"
+mount option to allow disabling the CIFS Unix Extensions for just
+that mount. Fix hang on spinlock in find_writable_file (race when
+reopening file after session crash).
Version 1.49
------------
diff --git a/fs/cifs/README b/fs/cifs/README
index 85f1eb14083..b806b11b556 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -444,6 +444,13 @@ A partial list of the supported mount options follows:
noposixpaths If CIFS Unix extensions are supported, do not request
posix path name support (this may cause servers to
reject creatingfile with certain reserved characters).
+ nounix Disable the CIFS Unix Extensions for this mount (tree
+ connection). This is rarely needed, but it may be useful
+ in order to turn off multiple settings all at once (ie
+ posix acls, posix locks, posix paths, symlink support
+ and retrieving uids/gids/mode from the server) or to
+ work around a bug in server which implement the Unix
+ Extensions.
nobrl Do not send byte range lock requests to the server.
This is necessary for certain applications that break
with cifs style mandatory byte range locks (and most
@@ -451,6 +458,12 @@ A partial list of the supported mount options follows:
byte range locks).
remount remount the share (often used to change from ro to rw mounts
or vice versa)
+ servern Specify the server 's netbios name (RFC1001 name) to use
+ when attempting to setup a session to the server. This is
+ This is needed for mounting to some older servers (such
+ as OS/2 or Windows 98 and Windows ME) since they do not
+ support a default server name. A server name can be up
+ to 15 characters long and is usually uppercased.
sfu When the CIFS Unix Extensions are not negotiated, attempt to
create device files and fifos in a format compatible with
Services for Unix (SFU). In addition retrieve bits 10-12
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index d7bd51575fd..29d4b271525 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -82,8 +82,7 @@ u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for
v) mount check for unmatched uids
-w) Add mount option for Linux extension disable per mount, and partial
-disable per mount (uid off, symlink/fifo/mknod on but what about posix acls?)
+w) Add support for new vfs entry points for setlease and fallocate
x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of
processes can proceed better in parallel (on the server)
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e13592afca9..894b1f7b299 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1904,6 +1904,25 @@ static int cifs_readpage(struct file *file, struct page *page)
return rc;
}
+static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
+{
+ struct cifsFileInfo *open_file;
+
+ read_lock(&GlobalSMBSeslock);
+ list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
+ if (open_file->closePend)
+ continue;
+ if (open_file->pfile &&
+ ((open_file->pfile->f_flags & O_RDWR) ||
+ (open_file->pfile->f_flags & O_WRONLY))) {
+ read_unlock(&GlobalSMBSeslock);
+ return 1;
+ }
+ }
+ read_unlock(&GlobalSMBSeslock);
+ return 0;
+}
+
/* We do not want to update the file size from server for inodes
open for write - to avoid races with writepage extending
the file - in the future we could consider allowing
@@ -1912,19 +1931,13 @@ static int cifs_readpage(struct file *file, struct page *page)
page caching in the current Linux kernel design */
int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
{
- struct cifsFileInfo *open_file = NULL;
-
- if (cifsInode)
- open_file = find_writable_file(cifsInode);
+ if (!cifsInode)
+ return 1;
- if (open_file) {
+ if (is_inode_writable(cifsInode)) {
+ /* This inode is open for write at least once */
struct cifs_sb_info *cifs_sb;
- /* there is not actually a write pending so let
- this handle go free and allow it to
- be closable if needed */
- atomic_dec(&open_file->wrtPending);
-
cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) {
/* since no page cache to corrupt on directio
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 2ea027dda21..892be9b4d1f 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -372,6 +372,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* 2000 big enough to fit max user, domain, NOS name etc. */
str_area = kmalloc(2000, GFP_KERNEL);
+ if (str_area == NULL) {
+ cifs_small_buf_release(smb_buf);
+ return -ENOMEM;
+ }
bcc_ptr = str_area;
ses->flags &= ~CIFS_SES_LANMAN;
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 6874785bb65..901dc55e9f5 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -958,36 +958,22 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
ssize_t ret2;
size_t bytes;
- dio->bio = NULL;
dio->inode = inode;
dio->rw = rw;
dio->blkbits = blkbits;
dio->blkfactor = inode->i_blkbits - blkbits;
- dio->start_zero_done = 0;
- dio->size = 0;
dio->block_in_file = offset >> blkbits;
- dio->blocks_available = 0;
- dio->cur_page = NULL;
- dio->boundary = 0;
- dio->reap_counter = 0;
dio->get_block = get_block;
dio->end_io = end_io;
- dio->map_bh.b_private = NULL;
- dio->map_bh.b_state = 0;
dio->final_block_in_bio = -1;
dio->next_block_for_io = -1;
- dio->page_errors = 0;
- dio->io_error = 0;
- dio->result = 0;
dio->iocb = iocb;
dio->i_size = i_size_read(inode);
spin_lock_init(&dio->bio_lock);
dio->refcount = 1;
- dio->bio_list = NULL;
- dio->waiter = NULL;
/*
* In case of non-aligned buffers, we may need 2 more
@@ -995,8 +981,6 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
*/
if (unlikely(dio->blkfactor))
dio->pages_in_io = 2;
- else
- dio->pages_in_io = 0;
for (seg = 0; seg < nr_segs; seg++) {
user_addr = (unsigned long)iov[seg].iov_base;
@@ -1184,7 +1168,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
}
}
- dio = kmalloc(sizeof(*dio), GFP_KERNEL);
+ dio = kzalloc(sizeof(*dio), GFP_KERNEL);
retval = -ENOMEM;
if (!dio)
goto out;
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 131954b3fb9..5d40ad13ab5 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -357,6 +357,10 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
ecryptfs_printk(KERN_DEBUG, "Is a special file; returning\n");
goto out;
}
+ if (special_file(lower_inode->i_mode)) {
+ ecryptfs_printk(KERN_DEBUG, "Is a special file; returning\n");
+ goto out;
+ }
if (!nd) {
ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave"
"as we *think* we are about to unlink\n");
diff --git a/fs/exec.c b/fs/exec.c
index 7bdea7937ee..c21a8cc0627 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -780,18 +780,11 @@ static int de_thread(struct task_struct *tsk)
int count;
/*
- * Tell all the sighand listeners that this sighand has
- * been detached. The signalfd_detach() function grabs the
- * sighand lock, if signal listeners are present on the sighand.
- */
- signalfd_detach(tsk);
-
- /*
* If we don't share sighandlers, then we aren't sharing anything
* and we can just re-use it all.
*/
if (atomic_read(&oldsighand->count) <= 1) {
- BUG_ON(atomic_read(&sig->count) != 1);
+ signalfd_detach(tsk);
exit_itimers(sig);
return 0;
}
@@ -930,12 +923,11 @@ static int de_thread(struct task_struct *tsk)
sig->flags = 0;
no_thread_group:
+ signalfd_detach(tsk);
exit_itimers(sig);
if (leader)
release_task(leader);
- BUG_ON(atomic_read(&sig->count) != 1);
-
if (atomic_read(&oldsighand->count) == 1) {
/*
* Now that we nuked the rest of the thread group,
@@ -1084,9 +1076,12 @@ int flush_old_exec(struct linux_binprm * bprm)
*/
current->mm->task_size = TASK_SIZE;
- if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
- file_permission(bprm->file, MAY_READ) ||
- (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
+ if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) {
+ suid_keys(current);
+ set_dumpable(current->mm, suid_dumpable);
+ current->pdeath_signal = 0;
+ } else if (file_permission(bprm->file, MAY_READ) ||
+ (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
suid_keys(current);
set_dumpable(current->mm, suid_dumpable);
}
@@ -1177,8 +1172,10 @@ void compute_creds(struct linux_binprm *bprm)
{
int unsafe;
- if (bprm->e_uid != current->uid)
+ if (bprm->e_uid != current->uid) {
suid_keys(current);
+ current->pdeath_signal = 0;
+ }
exec_keys(current);
task_lock(current);
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index bc618593366..664c164aa67 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -566,6 +566,9 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
struct jffs2_full_dirent **prev = &dir_f->dents;
uint32_t nhash = full_name_hash(name, namelen);
+ /* We don't actually want to reserve any space, but we do
+ want to be holding the alloc_sem when we write to flash */
+ down(&c->alloc_sem);
down(&dir_f->sem);
while ((*prev) && (*prev)->nhash <= nhash) {
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 965625a0977..ee4814dd98f 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -320,7 +320,21 @@ int proc_pid_status(struct task_struct *task, char *buffer)
return buffer - orig;
}
-static clock_t task_utime(struct task_struct *p)
+/*
+ * Use precise platform statistics if available:
+ */
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+static cputime_t task_utime(struct task_struct *p)
+{
+ return p->utime;
+}
+
+static cputime_t task_stime(struct task_struct *p)
+{
+ return p->stime;
+}
+#else
+static cputime_t task_utime(struct task_struct *p)
{
clock_t utime = cputime_to_clock_t(p->utime),
total = utime + cputime_to_clock_t(p->stime);
@@ -337,10 +351,10 @@ static clock_t task_utime(struct task_struct *p)
}
utime = (clock_t)temp;
- return utime;
+ return clock_t_to_cputime(utime);
}
-static clock_t task_stime(struct task_struct *p)
+static cputime_t task_stime(struct task_struct *p)
{
clock_t stime;
@@ -349,10 +363,12 @@ static clock_t task_stime(struct task_struct *p)
* the total, to make sure the total observed by userspace
* grows monotonically - apps rely on that):
*/
- stime = nsec_to_clock_t(p->se.sum_exec_runtime) - task_utime(p);
+ stime = nsec_to_clock_t(p->se.sum_exec_runtime) -
+ cputime_to_clock_t(task_utime(p));
- return stime;
+ return clock_t_to_cputime(stime);
}
+#endif
static int do_task_stat(struct task_struct *task, char *buffer, int whole)
{
@@ -368,8 +384,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
unsigned long long start_time;
unsigned long cmin_flt = 0, cmaj_flt = 0;
unsigned long min_flt = 0, maj_flt = 0;
- cputime_t cutime, cstime;
- clock_t utime, stime;
+ cputime_t cutime, cstime, utime, stime;
unsigned long rsslim = 0;
char tcomm[sizeof(task->comm)];
unsigned long flags;
@@ -387,8 +402,7 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
sigemptyset(&sigign);
sigemptyset(&sigcatch);
- cutime = cstime = cputime_zero;
- utime = stime = 0;
+ cutime = cstime = utime = stime = cputime_zero;
rcu_read_lock();
if (lock_task_sighand(task, &flags)) {
@@ -414,15 +428,15 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
do {
min_flt += t->min_flt;
maj_flt += t->maj_flt;
- utime += task_utime(t);
- stime += task_stime(t);
+ utime = cputime_add(utime, task_utime(t));
+ stime = cputime_add(stime, task_stime(t));
t = next_thread(t);
} while (t != task);
min_flt += sig->min_flt;
maj_flt += sig->maj_flt;
- utime += cputime_to_clock_t(sig->utime);
- stime += cputime_to_clock_t(sig->stime);
+ utime = cputime_add(utime, sig->utime);
+ stime = cputime_add(stime, sig->stime);
}
sid = signal_session(sig);
@@ -471,8 +485,8 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole)
cmin_flt,
maj_flt,
cmaj_flt,
- utime,
- stime,
+ cputime_to_clock_t(utime),
+ cputime_to_clock_t(stime),
cputime_to_clock_t(cutime),
cputime_to_clock_t(cstime),
priority,
diff --git a/fs/signalfd.c b/fs/signalfd.c
index 7b941abbcde..a8e293d3003 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -56,12 +56,18 @@ static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk)
sighand = lock_task_sighand(lk->tsk, &lk->flags);
rcu_read_unlock();
- if (sighand && !ctx->tsk) {
+ if (!sighand)
+ return 0;
+
+ if (!ctx->tsk) {
unlock_task_sighand(lk->tsk, &lk->flags);
- sighand = NULL;
+ return 0;
}
- return sighand != NULL;
+ if (lk->tsk->tgid == current->tgid)
+ lk->tsk = current;
+
+ return 1;
}
static void signalfd_unlock(struct signalfd_lockctx *lk)
@@ -331,7 +337,7 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
init_waitqueue_head(&ctx->wqh);
ctx->sigmask = sigmask;
- ctx->tsk = current;
+ ctx->tsk = current->group_leader;
sighand = current->sighand;
/*
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 135353f8a29..5afe2a26f5d 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -248,12 +248,7 @@ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
{
- if (sysfs_hash_and_remove(kobj->sd, attr->attr.name) < 0) {
- printk(KERN_ERR "%s: "
- "bad dentry or inode or no such file: \"%s\"\n",
- __FUNCTION__, attr->attr.name);
- dump_stack();
- }
+ sysfs_hash_and_remove(kobj->sd, attr->attr.name);
}
EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 048e6054c2f..83e76b3813c 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -762,12 +762,15 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd)
static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
+ struct dentry *ret = NULL;
struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
struct sysfs_dirent * sd;
struct bin_attribute *bin_attr;
struct inode *inode;
int found = 0;
+ mutex_lock(&sysfs_mutex);
+
for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
if (sysfs_type(sd) &&
!strcmp(sd->s_name, dentry->d_name.name)) {
@@ -778,14 +781,14 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
/* no such entry */
if (!found)
- return NULL;
+ goto out_unlock;
/* attach dentry and inode */
inode = sysfs_get_inode(sd);
- if (!inode)
- return ERR_PTR(-ENOMEM);
-
- mutex_lock(&sysfs_mutex);
+ if (!inode) {
+ ret = ERR_PTR(-ENOMEM);
+ goto out_unlock;
+ }
if (inode->i_state & I_NEW) {
/* initialize inode according to type */
@@ -815,9 +818,9 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
sysfs_instantiate(dentry, inode);
sysfs_attach_dentry(sd, dentry);
+ out_unlock:
mutex_unlock(&sysfs_mutex);
-
- return NULL;
+ return ret;
}
const struct inode_operations sysfs_dir_inode_operations = {
@@ -942,6 +945,8 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
if (error)
goto out_drop;
+ mutex_lock(&sysfs_mutex);
+
dup_name = sd->s_name;
sd->s_name = new_name;
@@ -949,8 +954,6 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
d_add(new_dentry, NULL);
d_move(sd->s_dentry, new_dentry);
- mutex_lock(&sysfs_mutex);
-
sysfs_unlink_sibling(sd);
sysfs_get(new_parent_sd);
sysfs_put(sd->s_parent);