patch-2.1.48 linux/fs/namei.c

Next file: linux/fs/nfs/dir.c
Previous file: linux/fs/inode.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.47/linux/fs/namei.c linux/fs/namei.c
@@ -240,45 +240,44 @@
 	struct dentry * result;
 	struct inode *dir = parent->d_inode;
 
-	result = ERR_PTR(-ENOTDIR);
-	if (dir->i_op && dir->i_op->lookup) {
-		down(&dir->i_sem);
-		result = d_lookup(parent, name);
-		if (!result) {
-			int error;
-			result = d_alloc(parent, name);
-			error = dir->i_op->lookup(dir, result);
-			if (error) {
-				d_free(result);
-				result = ERR_PTR(error);
-			}
+	down(&dir->i_sem);
+	result = d_lookup(parent, name);
+	if (!result) {
+		int error;
+		result = d_alloc(parent, name);
+		error = dir->i_op->lookup(dir, result);
+		if (error) {
+			d_free(result);
+			result = ERR_PTR(error);
 		}
-		up(&dir->i_sem);
 	}
+	up(&dir->i_sem);
 	return result;
 }
 
-/* Internal lookup() using the new generic dcache. */
+/*
+ * Internal lookup() using the new generic dcache.
+ *
+ * Note the revalidation: we have to drop the dcache
+ * lock when we revalidate, so we need to update the
+ * counts around it.
+ */
 static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
 {
 	struct dentry * dentry = d_lookup(parent, name);
 
-	if (dentry) {
-		if (dentry->d_revalidate) {
-			/* spin_unlock(&dentry_lock); */
-			dentry = dentry->d_revalidate(dentry);
-			/* spin_lock(&dentry_lock); */
-		}
-
-		/*
-		 * The parent d_count _should_ be at least 2: one for the
-		 * dentry we found, and one for the fact that we are using
-		 * it.
-		 */
-		if (parent->d_count <= 1) {
-			printk("lookup of %s success in %s, but parent count is %d\n",
-				dentry->d_name.name, parent->d_name.name, parent->d_count);
+	if (dentry && dentry->d_revalidate) {
+		int validated, (*revalidate)(struct dentry *) = dentry->d_revalidate;
+		struct dentry * save;
+
+		dentry->d_count++;
+		validated = revalidate(dentry);
+		save = dentry;
+		if (!validated) {
+			d_drop(dentry);
+			dentry = NULL;
 		}
+		dput(save);
 	}
 	return dentry;
 }
@@ -311,15 +310,8 @@
 /* In difference to the former version, lookup() no longer eats the dir. */
 static struct dentry * lookup(struct dentry * dir, struct qstr * name)
 {
-	int err;
 	struct dentry * result;
 
-	/* Check permissions before traversing mount-points. */
-	err = permission(dir->d_inode, MAY_EXEC);
-	result = ERR_PTR(err);
- 	if (err)
-		goto done_error;
-
 	result = reserved_lookup(dir, name);
 	if (result)
 		goto done_noerror;
@@ -334,7 +326,6 @@
 done_noerror:
 		result = dget(result->d_mounts);
 	}
-done_error:
 	return result;
 }
 
@@ -396,14 +387,26 @@
 
 	/* At this point we know we have a real path component. */
 	for(;;) {
-		int len;
+		int len, err;
 		unsigned long hash;
 		struct qstr this;
+		struct inode *inode;
 		char c, follow;
 
 		dentry = ERR_PTR(-ENOENT);
-		if (!base->d_inode)
+		inode = base->d_inode;
+		if (!inode)
+			break;
+
+		dentry = ERR_PTR(-ENOTDIR);
+		if (!inode->i_op || !inode->i_op->lookup)
+			break;
+
+		err = permission(inode, MAY_EXEC);
+		dentry = ERR_PTR(err);
+ 		if (err)
 			break;
+
 		this.name = name;
 		hash = init_name_hash();
 		len = 0;
@@ -831,6 +834,10 @@
 
 	dir = lock_parent(dentry);
 
+	error = -ENOENT;
+	if (!dentry->d_inode)
+		goto exit_lock;
+
 	error = -EROFS;
 	if (IS_RDONLY(dir))
 		goto exit_lock;
@@ -890,11 +897,11 @@
 	if (IS_ERR(dentry))
 		goto exit;
 
+	dir = lock_parent(dentry);
+
 	error = -EEXIST;
 	if (dentry->d_inode)
-		goto exit;
-
-	dir = lock_parent(dentry);
+		goto exit_lock;
 
 	error = -EROFS;
 	if (IS_RDONLY(dir))
@@ -1037,13 +1044,19 @@
 		down(s2);
 	} else if (s1 == s2) {
 		down(s1);
-		atomic_dec(&s1->count);
 	} else {
 		down(s2);
 		down(s1);
 	}
 }
 
+static inline void double_up(struct semaphore *s1, struct semaphore *s2)
+{
+	up(s1);
+	if (s1 != s2)
+		up(s2);
+}
+
 static inline int is_reserved(struct dentry *dentry)
 {
 	if (dentry->d_name.name[0] == '.') {
@@ -1126,8 +1139,7 @@
 	error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
 
 exit_lock:
-	up(&new_dir->i_sem);
-	up(&old_dir->i_sem);
+	double_up(&new_dir->i_sem, &old_dir->i_sem);
 	dput(new_dentry);
 exit_old:
 	dput(old_dentry);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov