Skip to content

Commit

Permalink
msdosfs: fix deleted-but-open files handling.
Browse files Browse the repository at this point in the history
When deleting a file, msdosfs keeps its denode in the denode cache until it is
reclaimed.  This causes a collision in the cache when recycling the directory
entry of a deleted but still open file for a new or renamed file.  This
collision was incorrecly handled resulting in a kernel panic (rename case) or
syscall error and corrupted in-core state (new file case).

Fix by allowing denodes pointing to the same directory entry to coexist in the
cache as long as a single one of them represents an existing file.

Reported-by: corecore@
Dragonfly-bug: <http://bugs.dragonflybsd.org/issue1286>
(cherry picked from commit 629f33a)
  • Loading branch information
nthery committed Mar 1, 2009
1 parent 89a8424 commit fe7717d
Showing 1 changed file with 21 additions and 5 deletions.
26 changes: 21 additions & 5 deletions sys/vfs/msdosfs/msdosfs_denode.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ static void msdosfs_hashrem (struct denode *dep);

static MALLOC_DEFINE(M_MSDOSFSNODE, "MSDOSFS node", "MSDOSFS vnode private part");

/*
* Hash table caching denode instances.
*
* denodes are keyed by the disk location (cluster num, entry offset) of the
* directory entry of the file they represent.
*
* denodes representing deleted but still opened files are left in this cache
* until reclaimed. Deleted directory entries can be reused when files are
* renamed or new files created. As a consequence, several denodes associated
* with the same entry may coexist in this cache as long as a single one of
* them map to an existing file (de_refcnt > 0).
*
* R/w access to this cache is protected by dehash_token.
*/
static struct denode **dehashtbl;
static u_long dehash; /* size of hash table - 1 */
#define DEHASH(dev, dcl, doff) (dehashtbl[(minor(dev) + (dcl) + (doff) / \
Expand Down Expand Up @@ -164,6 +178,10 @@ msdosfs_hashget(cdev_t dev, u_long dirclust, u_long diroff)
return (NULL);
}

/*
* Try to insert specified denode into the hash table. Return 0 on success
* and EBUSY if there is already a denode with the same key.
*/
static
int
msdosfs_hashins(struct denode *dep)
Expand All @@ -176,12 +194,10 @@ msdosfs_hashins(struct denode *dep)
while ((deq = *depp) != NULL) {
if (deq->de_dev == dep->de_dev &&
deq->de_dirclust == dep->de_dirclust &&
deq->de_diroffset == dep->de_diroffset) {
deq->de_diroffset == dep->de_diroffset &&
deq->de_refcnt > 0) {
lwkt_reltoken(&ilock);
if (dep->de_refcnt)
return(EBUSY);
else
return(EINVAL);
return(EBUSY);
}
depp = &deq->de_next;
}
Expand Down

0 comments on commit fe7717d

Please sign in to comment.