Commit 22e1d96f authored by Phoebe Buckheister's avatar Phoebe Buckheister 🦎

Merge branch 'v6-revert-properly-dispose-old-dentries' into 'v6'

Revert "client: let lookup_slow properly dispose of old dentries for us"

See merge request !384
parents 0ce2b142 2644ce52
......@@ -119,6 +119,11 @@ check_function \
KERNEL_HAS_SUPER_SETUP_BDI_NAME \
linux/fs.h
check_function \
have_submounts "int (struct dentry *parent)" \
KERNEL_HAS_HAVE_SUBMOUNTS \
linux/dcache.h
# we have to communicate with the calling makefile somehow. since we can't really use the return
# code of this script, we'll echo a special string at the end of our output for the caller to
# detect and remove again.
......
......@@ -79,7 +79,18 @@ int FhgfsOps_revalidateIntent(struct dentry* dentry, unsigned flags)
FhgfsOpsHelper_logOp(Log_SPAM, app, dentry, inode, logContext);
if(!inode || !parentInode || is_bad_inode(inode) )
{
if(inode && S_ISDIR(inode->i_mode) )
{
if(have_submounts(dentry) )
goto cleanup_put_parent;
shrink_dcache_parent(dentry);
}
d_drop(dentry);
goto cleanup_put_parent;
}
// active dentry => remote-stat and local-compare
......@@ -121,6 +132,8 @@ int __FhgfsOps_revalidateIntent(struct dentry* parentDentry, struct dentry* dent
FhgfsInode* fhgfsInode = BEEGFS_INODE(inode);
bool cacheValid = FhgfsInode_isCacheValid(fhgfsInode, inode->i_mode, cfg);
int isValid = 0; // quasi-boolean (return value)
bool needDrop = false;
FhgfsIsizeHints iSizeHints;
......@@ -129,7 +142,10 @@ int __FhgfsOps_revalidateIntent(struct dentry* parentDentry, struct dentry* dent
if (cacheValid)
return 1;
{
isValid = 1;
return isValid;
}
if(IS_ROOT(dentry) )
fhgfsStatPtr = NULL;
......@@ -165,7 +181,10 @@ int __FhgfsOps_revalidateIntent(struct dentry* parentDentry, struct dentry* dent
FhgfsInode_entryInfoReadUnlock(parentFhgfsInode); // UNLOCK parentInfo
if (unlikely(remotingRes != FhgfsOpsErr_SUCCESS) )
return 0;
{
needDrop = true;
goto out;
}
if (outInfo.revalidateRes != FhgfsOpsErr_SUCCESS)
{
......@@ -173,7 +192,8 @@ int __FhgfsOps_revalidateIntent(struct dentry* parentDentry, struct dentry* dent
Logger_logErrFormatted(log, logContext, "Unexpected revalidate info missing: %s",
entryInfo->fileName);
return 0;
needDrop = true;
goto out;
}
// check the stat result here and set fhgfsStatPtr accordingly
......@@ -189,11 +209,21 @@ int __FhgfsOps_revalidateIntent(struct dentry* parentDentry, struct dentry* dent
entryInfo->fileName);
// now its getting difficult as there is an unexpected error
return 0;
needDrop = true;
goto out;
}
}
return !__FhgfsOps_refreshInode(app, inode, fhgfsStatPtr, &iSizeHints);
if (!__FhgfsOps_refreshInode(app, inode, fhgfsStatPtr, &iSizeHints) )
isValid = 1;
else
isValid = 0;
out:
if (needDrop)
d_drop(dentry);
return isValid;
}
/**
......
......@@ -351,3 +351,169 @@ int os_generic_write_checks(struct file* filp, loff_t* offset, size_t* size, int
return 0;
}
#endif
#ifndef KERNEL_HAS_HAVE_SUBMOUNTS
/**
* enum d_walk_ret - action to talke during tree walk
* @D_WALK_CONTINUE: contrinue walk
* @D_WALK_QUIT: quit walk
* @D_WALK_NORETRY: quit when retry is needed
* @D_WALK_SKIP: skip this dentry and its children
*/
enum d_walk_ret {
D_WALK_CONTINUE,
D_WALK_QUIT,
D_WALK_NORETRY,
D_WALK_SKIP,
};
/*
* Search for at least 1 mount point in the dentry's subdirs.
* We descend to the next level whenever the d_subdirs
* list is non-empty and continue searching.
*/
static enum d_walk_ret check_mount(void *data, struct dentry *dentry)
{
int *ret = data;
if (d_mountpoint(dentry)) {
*ret = 1;
return D_WALK_QUIT;
}
return D_WALK_CONTINUE;
}
/**
* d_walk - walk the dentry tree
* @parent: start of walk
* @data: data passed to @enter() and @finish()
* @enter: callback when first entering the dentry
* @finish: callback when successfully finished the walk
*
* The @enter() and @finish() callbacks are called with d_lock held.
*/
static void d_walk(struct dentry *parent, void *data,
enum d_walk_ret (*enter)(void *, struct dentry *),
void (*finish)(void *))
{
struct dentry *this_parent;
struct list_head *next;
unsigned seq = 0;
enum d_walk_ret ret;
bool retry = true;
again:
read_seqbegin_or_lock(&rename_lock, &seq);
this_parent = parent;
spin_lock(&this_parent->d_lock);
ret = enter(data, this_parent);
switch (ret) {
case D_WALK_CONTINUE:
break;
case D_WALK_QUIT:
case D_WALK_SKIP:
goto out_unlock;
case D_WALK_NORETRY:
retry = false;
break;
}
repeat:
next = this_parent->d_subdirs.next;
resume:
while (next != &this_parent->d_subdirs) {
struct list_head *tmp = next;
struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;
if (unlikely(dentry->d_flags & DCACHE_DENTRY_CURSOR))
continue;
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
ret = enter(data, dentry);
switch (ret) {
case D_WALK_CONTINUE:
break;
case D_WALK_QUIT:
spin_unlock(&dentry->d_lock);
goto out_unlock;
case D_WALK_NORETRY:
retry = false;
break;
case D_WALK_SKIP:
spin_unlock(&dentry->d_lock);
continue;
}
if (!list_empty(&dentry->d_subdirs)) {
spin_unlock(&this_parent->d_lock);
spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_);
this_parent = dentry;
spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
goto repeat;
}
spin_unlock(&dentry->d_lock);
}
/*
* All done at this level ... ascend and resume the search.
*/
rcu_read_lock();
ascend:
if (this_parent != parent) {
struct dentry *child = this_parent;
this_parent = child->d_parent;
spin_unlock(&child->d_lock);
spin_lock(&this_parent->d_lock);
/* might go back up the wrong parent if we have had a rename. */
if (need_seqretry(&rename_lock, seq))
goto rename_retry;
/* go into the first sibling still alive */
do {
next = child->d_child.next;
if (next == &this_parent->d_subdirs)
goto ascend;
child = list_entry(next, struct dentry, d_child);
} while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
rcu_read_unlock();
goto resume;
}
if (need_seqretry(&rename_lock, seq))
goto rename_retry;
rcu_read_unlock();
if (finish)
finish(data);
out_unlock:
spin_unlock(&this_parent->d_lock);
done_seqretry(&rename_lock, seq);
return;
rename_retry:
spin_unlock(&this_parent->d_lock);
rcu_read_unlock();
BUG_ON(seq & 1);
if (!retry)
return;
seq = 1;
goto again;
}
/**
* have_submounts - check for mounts over a dentry
* @parent: dentry to check.
*
* Return true if the parent or its subdirectories contain
* a mount point
*/
int have_submounts(struct dentry *parent)
{
int ret = 0;
d_walk(parent, &ret, check_mount, NULL);
return ret;
}
#endif
......@@ -46,6 +46,10 @@ static inline int os_generic_permission(struct inode *inode, int mask);
extern int bdi_setup_and_register(struct backing_dev_info *bdi, char *name, unsigned int cap);
#endif
#ifndef KERNEL_HAS_HAVE_SUBMOUNTS
extern int have_submounts(struct dentry *parent);
#endif
/**
* generic_permission() compatibility function
*
......
mount0 = node.properties["client0"]["mount"]
mount1 = node.properties["client1"]["mount"]
on node do
cd mount0 do
shell "mkdir a"
shell "sudo mount -t tmpfs 66144c9bbabe13ecd8b5a43dfdee150a44ef6edc a"
end
cd mount1 do
shell "while ! stat a >/dev/null 2>&1; do sleep 0.1; done"
shell "rmdir a"
end
cd mount0 do
# need to stat the directory to cause d_revalidate. unmount will work too.
# stat must fail at some point, because the directory is gone.
shell "while stat a >/dev/null 2>&1; do sleep 0.1; done"
shell "! mount | grep 66144c9bbabe13ecd8b5a43dfdee150a44ef6edc"
end
end
# vim:ft=ruby
desc:
check that mounts are removed properly when their mountpoints are removed by a peer.
hosts:
node: [mgmtd, meta, storage, helperd, client, client]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment