[PATCH] More rmdir fixes (was: Linux-2.1.131..)

Alexander Viro (viro@math.psu.edu)
Fri, 4 Dec 1998 17:05:41 -0500 (EST)


On Wed, 2 Dec 1998, Linus Torvalds wrote:

>
> 2.1.131 is out there now - and will be the last kernel release for a
> while. I'm going to Finland for a week and a half, and will be back mid
> December. During that time I hope people will beat on this. I'll be able
> to read email when I'm gone, but as I haven't been back in over a year,
> I'm not very likely to.
>
> Alan, I have got any replies (positive or negative) about the VFS fixes in
> pre-2.1.131-3 (which are obviously in the real 131 too), so I hope that
> means that I successfully fixed all filesystems. The chance of that being
> true is remote, but hey, I can hope. If not, I assume you'll be doing
> your ac patches anyway (any bugs wrt rmdir() should be fairly obvious once
> seen), and people might as well consider those official..

Here comes the tail of rmdir fixes. I hope there will be no more
surprises in this area.
Summary:
a) sysvfs: handling of busy directories wasn't updated back
when we switched to dentries. Fixed (to new scheme).
b) qnx4: plugged an inode leak.
c) affs: directories behave as sticky there, but sticky bit wasn't
set in i_mode. Fixed.
d) ufs: this beast allows deletion of busy directory (as ext2 does),
but handling of this case wasn't updated (== stopped working). Fixed.
e) NFSD rmdir missed locking and quite a few tests. Fixed (see below)
f) filesystem-independant tests (e.g. S_ISDIR(dentry) ;-) moved from
filesystems to VFS (where the rest of them lived). Error codes made consistent
(IMHO the situation when 3 filesystems return different errors under the same
filesystem-independant conditions and 4th one flames and returns 0 is somewhat
over the top).
g) do_rmdir() now does dentry lookup and locking. All tests and actual
call of rmdir() method moved to new function - VFS_rmdir(). It has the same
interface as rmdir() method. It has been made public and included into the
export list. NFSD rmdir() does required locking and calls VFS_rmdir().

Remaining problems:
UMSDOS rename() is still slightly broken - it returns EBUSY if the
target already exists and is an empty directory (side effect of new
busy-detection scheme). I'll fix it as soon as I'll get to rename() cleanup.
NFSD should do some tests in unlink() (and maybe in some other
operations).
Cheers,
Al
Patch against 2.1.131 follows:

diff -u --recursive --new-file v2.1.131/linux/fs/ChangeLog linux/fs/ChangeLog
--- v2.1.131/linux/fs/ChangeLog Tue Oct 25 12:10:14 1994
+++ linux/fs/ChangeLog Fri Dec 4 11:48:58 1998
@@ -8,3 +8,67 @@
* fcntl.c (sys_fcntl): Add more of a security check to the
F_SETOWN fcntl().

+[Tons of changes missed, indeed. This list is worth restarting since
+at least some fixes WILL break third-party filesystems. Sorry, but
+there was no other way to fix rmdir/rename deadlock, for one.]
+
+Wed Dec 2 (Linus, fill the rest, please)
+
+ * namei.c (do_rmdir) and rmdir method in filesystems:
+ Locking of directory we remove was taken to VFS.
+ See comments in do_rmdir(). Unfixed filesystems
+ will bloody likely deadlock in rmdir().
+
+Thu Dec 3 17:25:31 1998 Al Viro (viro@math.psu.edu)
+
+ * namei.c (do_rmdir):
+ Reject non-directories here.
+ Two (probably) obsolete checks moved here too: we fail if
+ the directory we remove is the same as parent (BUG: we
+ serve mountpoints later) or if it lives on a different
+ device.
+ * sysvfs/namei.c (sysv_rmdir):
+ Bugectomy: old check for victim being busy (inode->i_count)
+ wasn't replaced (with checking dentry->d_count) and escaped
+ Linus in the last round of changes. Shot and buried.
+
+Fri Dec 4 00:54:12 1998 AV
+
+ * namei.c (check_sticky): New function check_sticky(dir, inode).
+ If dir is sticky check whether we can unlink/rmdir/rename
+ the inode. Returns 1 if we can't. If dir isn't sticky -
+ return 0 (i.e. no objections). Some filesystems require
+ suser() here; some are fine with CAP_FOWNER. The later
+ seems more reasonable.
+ * namei.c (do_rmdir):
+ Moved the check for sticky bit here.
+ * affs/{inode,namei}.c:
+ All AFFS directories have sticky semantics (i.e. non-owner
+ having write permisssions on directory can unlink/rmdir/rename
+ only the files he owns), but AFFS didn't set S_ISVTX on them.
+ Fixed. NB: maybe this behaviour should be controlled by mount
+ option. Obvious values being 'sticky' (current behaviour),
+ 'nonsticky' (normal behaviour) and maybe some play on 'D'
+ permissions bit. FIXME.
+ * qnx4/namei.c (qnx4_rmdir):
+ Plugged inode leak.
+ * ufs/namei.c (ufs_rmdir):
+ Changed handling of busy directory to new scheme.
+
+Fri Dec 4 10:30:58 1998 AV
+
+ * namei.c (VFS_rmdir): New function. It gets inode of the parent and
+ dentry of the victim, does all checks and applies fs-specific
+ rmdir() method. It should be called with semaphores down
+ on both the victim and its parent and with bumped d_count on
+ victim (see comments in do_rmdir).
+ * include/linux/fs.h: Added VFS_rmdir
+ * kernel/ksyms.c: Added VFS_rmdir to export list (for NFSD).
+ * nfsd/vfs.c: Fixed rmdir handling.
+
+ Remaining problems with rmdir:
+ UMSDOS_rename is broken. Call it with the dest. existing and
+ being an empty directory and you've got EBUSY. At least it
+ doesn't do any harm, so that will wait several days till rename
+ cleanup.
+ TODO: unlink handling in NFSD does no tests.
diff -u --recursive --new-file v2.1.131/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.1.131/linux/fs/affs/inode.c Fri May 8 01:58:04 1998
+++ linux/fs/affs/inode.c Thu Dec 3 20:10:38 1998
@@ -170,8 +170,11 @@
} else {
inode->i_op = &affs_file_inode_operations;
}
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
+ /* Maybe it should be controlled by mount parameter? */
+ inode->i_mode |= S_ISVTX;
inode->i_op = &affs_dir_inode_operations;
+ }
else if (S_ISLNK(inode->i_mode))
inode->i_op = &affs_symlink_inode_operations;
}
diff -u --recursive --new-file v2.1.131/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.1.131/linux/fs/affs/namei.c Thu Dec 3 16:58:49 1998
+++ linux/fs/affs/namei.c Fri Dec 4 00:19:14 1998
@@ -319,7 +319,7 @@
error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
if (error)
goto out_iput;
- inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
+ inode->i_mode = S_IFDIR | S_ISVTX | (mode & 0777 & ~current->fs->umask);
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
d_instantiate(dentry,inode);
mark_inode_dirty(inode);
@@ -360,17 +360,6 @@
if (!(bh = affs_find_entry(dir,dentry,&ino)))
goto rmdir_done;

- retval = -EPERM;
- if (current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
- goto rmdir_done;
- if (inode->i_dev != dir->i_dev)
- goto rmdir_done;
- if (inode == dir) /* we may not delete ".", but "../dir" is ok */
- goto rmdir_done;
- retval = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode))
- goto rmdir_done;
/*
* Make sure the directory is empty and the dentry isn't busy.
*/
diff -u --recursive --new-file v2.1.131/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.1.131/linux/fs/ext2/namei.c Thu Dec 3 16:58:49 1998
+++ linux/fs/ext2/namei.c Fri Dec 4 00:20:29 1998
@@ -643,21 +643,7 @@
inode = dentry->d_inode;
DQUOT_INIT(inode);

- retval = -EPERM;
- if ((dir->i_mode & S_ISVTX) &&
- current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
- goto end_rmdir;
- if (inode == dir) /* we may not delete ".", but "../dir" is ok */
- goto end_rmdir;
-
- retval = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode))
- goto end_rmdir;
-
retval = -EIO;
- if (inode->i_dev != dir->i_dev)
- goto end_rmdir;
if (le32_to_cpu(de->inode) != inode->i_ino)
goto end_rmdir;

diff -u --recursive --new-file v2.1.131/linux/fs/hfs/dir.c linux/fs/hfs/dir.c
--- v2.1.131/linux/fs/hfs/dir.c Thu Dec 3 16:58:49 1998
+++ linux/fs/hfs/dir.c Fri Dec 4 08:29:03 1998
@@ -337,9 +337,6 @@
struct hfs_cat_key key;
int error;

- if (parent == inode) /* can't delete . */
- return -EPERM;
-
if (build_key(&key, parent, dentry->d_name.name,
dentry->d_name.len))
return -EPERM;
diff -u --recursive --new-file v2.1.131/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.1.131/linux/fs/minix/namei.c Thu Dec 3 16:58:49 1998
+++ linux/fs/minix/namei.c Fri Dec 4 00:22:28 1998
@@ -429,21 +429,8 @@
retval = -ENOENT;
if (!bh)
goto end_rmdir;
- retval = -EPERM;
inode = dentry->d_inode;

- if ((dir->i_mode & S_ISVTX) &&
- current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
- goto end_rmdir;
- if (inode->i_dev != dir->i_dev)
- goto end_rmdir;
- if (inode == dir) /* we may not delete ".", but "../dir" is ok */
- goto end_rmdir;
- if (!S_ISDIR(inode->i_mode)) {
- retval = -ENOTDIR;
- goto end_rmdir;
- }
if (!empty_dir(inode)) {
retval = -ENOTEMPTY;
goto end_rmdir;
diff -u --recursive --new-file v2.1.131/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.1.131/linux/fs/msdos/namei.c Thu Dec 3 16:58:49 1998
+++ linux/fs/msdos/namei.c Thu Dec 3 18:16:11 1998
@@ -439,11 +439,6 @@
&bh, &de, &ino);
if (res < 0)
goto rmdir_done;
- res = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode))
- goto rmdir_done;
- if (dir->i_dev != inode->i_dev || dir == inode)
- printk("msdos_rmdir: impossible condition\n");
/*
* Check whether the directory is empty, then prune
* any child dentries and make sure it's not in use.
diff -u --recursive --new-file v2.1.131/linux/fs/namei.c linux/fs/namei.c
--- v2.1.131/linux/fs/namei.c Thu Dec 3 16:58:49 1998
+++ linux/fs/namei.c Fri Dec 4 12:21:26 1998
@@ -865,58 +865,67 @@
dput(d2);
}

-static inline int do_rmdir(const char * name)
-{
- int error;
- struct dentry *dir;
- struct dentry *dentry;
-
- dentry = lookup_dentry(name, NULL, 0);
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto exit;
+/*
+ * It's inline, so penalty for filesystems that don't use sticky bit is
+ * minimal.
+ */

- dir = dget(dentry->d_parent);
+static inline int check_sticky(struct inode *dir, struct inode *inode)
+{
+ if (!(dir->i_mode & S_ISVTX))
+ return 0;
+ if (inode->i_uid == current->fsuid)
+ return 0;
+ if (dir->i_uid == current->fsuid)
+ return 0;
+ return !capable(CAP_FOWNER);
+}

- error = -ENOENT;
- if (!dentry->d_inode)
- goto exit;
- /*
- * The dentry->d_count stuff confuses d_delete() enough to
- * not kill the inode from under us while it is locked. This
- * wouldn't be needed, except the dentry semaphore is really
- * in the inode, not in the dentry..
- */
- dentry->d_count++;
- double_lock(dir, dentry);
- if (dentry->d_parent != dir)
- goto exit_lock;
+int VFS_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ int error;

- error = -EROFS;
- if (IS_RDONLY(dir->d_inode))
- goto exit_lock;
+ if (IS_RDONLY(dir))
+ return -EROFS;

- error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC);
+ error = permission(dir,MAY_WRITE | MAY_EXEC);
if (error)
- goto exit_lock;
+ return error;

/*
* A subdirectory cannot be removed from an append-only directory.
*/
- error = -EPERM;
- if (IS_APPEND(dir->d_inode))
- goto exit_lock;
+ if (IS_APPEND(dir))
+ return -EPERM;
+ /*
+ * Check the sticky bit.
+ */
+ if (check_sticky(dir, dentry->d_inode))
+ return -EPERM;

/* Disallow removals of mountpoints. */
- error = -EBUSY;
if (dentry->d_mounts != dentry->d_covers)
- goto exit_lock;
-
- error = -EPERM;
- if (!dir->d_inode->i_op || !dir->d_inode->i_op->rmdir)
- goto exit_lock;
+ return -EBUSY;

- DQUOT_INIT(dir->d_inode);
+ if (!dir->i_op || !dir->i_op->rmdir)
+ return -EPERM;
+ /*
+ * I suspect that these two checks are atavisms copied from minixfs
+ * and it looks like they can be dropped. Anyway, it will be simpler
+ * to drop them from here and even if those checks are needed they
+ * belong to VFS.
+ */
+ if (dir == dentry->d_inode)
+ return -EPERM;
+ if (dir->i_dev != dentry->d_inode->i_dev)
+ return -EPERM;
+ /*
+ * Non-directories can't be rmdir'd. It may confuse the heck of
+ * NFS and CODA. Testing it in VFS is the Right Thing (tm), anyway.
+ */
+ if (!S_ISDIR(dentry->d_inode->i_mode))
+ return -ENOTDIR;
+ DQUOT_INIT(dir);

/*
* We try to drop the dentry early: we should have
@@ -942,9 +951,42 @@
d_drop(dentry);
}

- error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry);
+ error = dir->i_op->rmdir(dir, dentry);
+
+ return error;
+}
+
+static inline int do_rmdir(const char * name)
+{
+ int error;
+ struct dentry *dir;
+ struct dentry *dentry;
+
+ dentry = lookup_dentry(name, NULL, 0);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto exit;
+
+ dir = dget(dentry->d_parent);
+
+ error = -ENOENT;
+ if (!dentry->d_inode)
+ goto exit;
+ /*
+ * The dentry->d_count stuff confuses d_delete() enough to
+ * not kill the inode from under us while it is locked. This
+ * wouldn't be needed, except the dentry semaphore is really
+ * in the inode, not in the dentry..
+ */
+ dentry->d_count++;
+ double_lock(dir, dentry);
+
+ /*
+ * Check that dentry still sits where it did and do the real stuff.
+ */
+ if (dentry->d_parent == dir)
+ error = VFS_rmdir(dir->d_inode, dentry);

-exit_lock:
dentry->d_count--;
double_unlock(dentry, dir);
exit:
diff -u --recursive --new-file v2.1.131/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.131/linux/fs/nfs/dir.c Thu Dec 3 16:58:50 1998
+++ linux/fs/nfs/dir.c Thu Dec 3 18:19:35 1998
@@ -718,6 +718,9 @@
*
* We update inode->i_nlink and free the inode prior to the operation
* to avoid possible races if the server reuses the inode.
+ *
+ * FIXME! We don't do it anymore (2.1.131) - it interacts badly with
+ * new rmdir(). -- AV
*/
static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
diff -u --recursive --new-file v2.1.131/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.1.131/linux/fs/nfsd/vfs.c Thu Dec 3 16:58:50 1998
+++ linux/fs/nfsd/vfs.c Fri Dec 4 13:00:06 1998
@@ -1076,25 +1076,49 @@
* FIXME!!
*
* This should do a double-lock on both rdentry and the parent
+ *
+ * Moreover, it should do checks *both* for unlink and rmdir
+ * cases. AV
*/
- err = fh_lock_parent(fhp, rdentry);
- if (err)
- goto out;
-
- DQUOT_INIT(dirp);
- if (type == S_IFDIR) {
- err = -ENOTDIR;
- if (dirp->i_op && dirp->i_op->rmdir)
- err = dirp->i_op->rmdir(dirp, rdentry);
- } else {
+ if (type != S_IFDIR) {
+ /* It's UNLINK */
+ err = fh_lock_parent(fhp, rdentry);
+ if (err)
+ goto out;
+
+ DQUOT_INIT(dirp);
err = -EPERM;
if (dirp->i_op && dirp->i_op->unlink)
err = dirp->i_op->unlink(dirp, rdentry);
+ DQUOT_DROP(dirp);
+ fh_unlock(fhp);
+
+ dput(rdentry);
+
+ } else {
+ /* It's RMDIR */
+ /* See comments in fs/namei.c:do_rmdir */
+ rdentry->d_count++;
+ nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem);
+ if (!fhp->fh_pre_mtime)
+ fhp->fh_pre_mtime = dirp->i_mtime;
+ fhp->fh_locked = 1;
+ /* CHECKME: Should we do something with the child? */
+
+ err = -ENOENT;
+ if (rdentry->d_parent->d_inode == dirp)
+ err = VFS_rmdir(dirp, rdentry);
+
+ rdentry->d_count--;
+ DQUOT_DROP(dirp);
+ if (!fhp->fh_post_version)
+ fhp->fh_post_version = dirp->i_version;
+ fhp->fh_locked = 0;
+ nfsd_double_up(&dirp->i_sem, &rdentry->d_inode->i_sem);
+
+ dput(rdentry);
}
- DQUOT_DROP(dirp);
- fh_unlock(fhp);

- dput(rdentry);
if (err)
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export))
diff -u --recursive --new-file v2.1.131/linux/fs/qnx4/namei.c linux/fs/qnx4/namei.c
--- v2.1.131/linux/fs/qnx4/namei.c Thu Dec 3 16:58:50 1998
+++ linux/fs/qnx4/namei.c Fri Dec 4 00:49:38 1998
@@ -168,29 +168,9 @@
if (bh == NULL) {
return -ENOENT;
}
- if ((inode = iget(dir->i_sb, ino)) == NULL) {
- QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
- retval = -EACCES;
- goto end_rmdir;
- }
- retval = -EPERM;
- if ((dir->i_mode & S_ISVTX) &&
- current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) {
- QNX4DEBUG(("qnx4: rmdir->capabilities\n"));
- goto end_rmdir;
- }
- if (inode->i_dev != dir->i_dev) {
- QNX4DEBUG(("qnx4: rmdir->different devices\n"));
- goto end_rmdir;
- }
- if (inode == dir) { /* we may not delete ".", but "../dir" is ok */
- QNX4DEBUG(("qnx4: inode==dir\n"));
- goto end_rmdir;
- }
- if (!S_ISDIR(inode->i_mode)) {
- QNX4DEBUG(("qnx4: rmdir->not a directory\n"));
- retval = -ENOTDIR;
+ inode = dentry->d_inode;
+ if (inode->i_ino != ino) {
+ retval = -EIO;
goto end_rmdir;
}
#if 0
diff -u --recursive --new-file v2.1.131/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.1.131/linux/fs/smbfs/dir.c Thu Dec 3 16:58:50 1998
+++ linux/fs/smbfs/dir.c Thu Dec 3 17:22:13 1998
@@ -469,10 +469,6 @@
struct inode *inode = dentry->d_inode;
int error;

- error = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode))
- goto out;
-
/*
* Close the directory if it's open.
*/
diff -u --recursive --new-file v2.1.131/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.1.131/linux/fs/sysv/namei.c Thu Dec 3 16:58:50 1998
+++ linux/fs/sysv/namei.c Fri Dec 4 00:41:09 1998
@@ -416,21 +416,8 @@
retval = -ENOENT;
if (!bh)
goto end_rmdir;
- retval = -EPERM;
inode = dentry->d_inode;

- if ((dir->i_mode & S_ISVTX) &&
- current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
- goto end_rmdir;
- if (inode->i_dev != dir->i_dev)
- goto end_rmdir;
- if (inode == dir) /* we may not delete ".", but "../dir" is ok */
- goto end_rmdir;
- if (!S_ISDIR(inode->i_mode)) {
- retval = -ENOTDIR;
- goto end_rmdir;
- }
if (!empty_dir(inode)) {
retval = -ENOTEMPTY;
goto end_rmdir;
@@ -439,7 +426,7 @@
retval = -ENOENT;
goto end_rmdir;
}
- if (inode->i_count > 1) {
+ if (!list_empty(&dentry->d_hash)) {
retval = -EBUSY;
goto end_rmdir;
}
diff -u --recursive --new-file v2.1.131/linux/fs/ufs/namei.c linux/fs/ufs/namei.c
--- v2.1.131/linux/fs/ufs/namei.c Thu Dec 3 16:58:50 1998
+++ linux/fs/ufs/namei.c Fri Dec 4 00:46:06 1998
@@ -683,46 +683,15 @@
if (inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize (inode, -1);

- retval = -EPERM;
- if ((dir->i_mode & S_ISVTX) &&
- current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !fsuser())
- goto end_rmdir;
- if (inode == dir) /* we may not delete ".", but "../dir" is ok */
- goto end_rmdir;
-
- retval = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode))
- goto end_rmdir;
-
retval = -EIO;
- if (inode->i_dev != dir->i_dev)
- goto end_rmdir;
if (SWAB32(de->d_ino) != inode->i_ino)
goto end_rmdir;

- /*
- * Prune any child dentries so that this dentry becomes negative.
- */
- if (dentry->d_count > 1) {
- ufs_warning (sb, "ufs_rmdir", "d_count=%d, pruning\n", dentry->d_count);
- shrink_dcache_parent(dentry);
- }
if (!ufs_empty_dir (inode))
retval = -ENOTEMPTY;
else if (SWAB32(de->d_ino) != inode->i_ino)
retval = -ENOENT;
else {
- if (dentry->d_count > 1) {
- /*
- * Are we deleting the last instance of a busy directory?
- * Better clean up if so.
- *
- * Make directory empty (it will be truncated when finally
- * dereferenced). This also inhibits ufs_add_entry.
- */
- inode->i_size = 0;
- }
retval = ufs_delete_entry (dir, de, bh);
dir->i_version = ++event;
}
@@ -739,6 +708,7 @@
inode->i_nlink);
inode->i_version = ++event;
inode->i_nlink = 0;
+ inode->i_size = 0;
mark_inode_dirty(inode);
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
diff -u --recursive --new-file v2.1.131/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.1.131/linux/fs/umsdos/namei.c Thu Dec 3 16:58:51 1998
+++ linux/fs/umsdos/namei.c Fri Dec 4 00:31:47 1998
@@ -1011,14 +1011,6 @@
if (!list_empty(&dentry->d_hash))
goto out;

- /* check the sticky bit */
- ret = -EPERM;
- if (is_sticky(dir, dentry->d_inode->i_uid)) {
-printk("umsdos_rmdir: %s/%s is sticky\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
- goto out;
- }
-
/* check whether the EMD is empty */
ret = -ENOTEMPTY;
empty = umsdos_isempty (dentry);
diff -u --recursive --new-file v2.1.131/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.1.131/linux/fs/vfat/namei.c Thu Dec 3 16:58:51 1998
+++ linux/fs/vfat/namei.c Thu Dec 3 18:35:54 1998
@@ -1416,12 +1416,6 @@
struct super_block *sb = dir->i_sb;
int res;

- if (!S_ISDIR(dentry->d_inode->i_mode)) {
- return -ENOTDIR;
- }
- if (dir->i_dev != dentry->d_inode->i_dev || dir == dentry->d_inode) {
- return -EBUSY;
- }
if (!list_empty(&dentry->d_hash))
return -EBUSY;

diff -u --recursive --new-file v2.1.131/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.131/linux/include/linux/fs.h Fri Nov 13 18:31:14 1998
+++ linux/include/linux/fs.h Fri Dec 4 13:26:04 1998
@@ -776,6 +776,7 @@
extern void put_write_access(struct inode *inode);
extern struct dentry * open_namei(const char * pathname, int flag, int mode);
extern struct dentry * do_mknod(const char * filename, int mode, dev_t dev);
+extern int VFS_rmdir(struct inode *dir, struct dentry *dentry);
extern int do_pipe(int *);

/* fs/dcache.c -- generic fs support functions */
diff -u --recursive --new-file v2.1.131/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.131/linux/kernel/ksyms.c Sat Nov 28 02:08:10 1998
+++ linux/kernel/ksyms.c Fri Dec 4 11:42:46 1998
@@ -172,6 +172,7 @@
EXPORT_SYMBOL(find_inode_number);
EXPORT_SYMBOL(is_subdir);
EXPORT_SYMBOL(get_unused_fd);
+EXPORT_SYMBOL(VFS_rmdir);

#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
EXPORT_SYMBOL(do_nfsservctl);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/