#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/namei.h>
#define dprintk(fmt, args...) do{}while(0)
+static struct dentry *
+find_acceptable_alias(struct dentry *result,
+ int (*acceptable)(void *context, struct dentry *dentry),
+ void *context)
+{
+ struct dentry *dentry, *toput = NULL;
+
+ spin_lock(&dcache_lock);
+ list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) {
+ dget_locked(dentry);
+ spin_unlock(&dcache_lock);
+ if (toput)
+ dput(toput);
+ if (dentry != result && acceptable(context, dentry)) {
+ dput(result);
+ return dentry;
+ }
+ spin_lock(&dcache_lock);
+ toput = dentry;
+ }
+ spin_unlock(&dcache_lock);
+
+ if (toput)
+ dput(toput);
+ return NULL;
+}
+
/**
* find_exported_dentry - helper routine to implement export_operations->decode_fh
* @sb: The &super_block identifying the filesystem
struct dentry *target_dir;
int err;
struct export_operations *nops = sb->s_export_op;
- struct list_head *le, *head;
- struct dentry *toput = NULL;
+ struct dentry *alias;
int noprogress;
-
+ char nbuf[NAME_MAX+1];
/*
* Attempt to find the inode.
/* there is no other dentry, so fail */
goto err_result;
}
- /* try any other aliases */
- spin_lock(&dcache_lock);
- head = &result->d_inode->i_dentry;
- list_for_each(le, head) {
- struct dentry *dentry = list_entry(le, struct dentry, d_alias);
- dget_locked(dentry);
- spin_unlock(&dcache_lock);
- if (toput)
- dput(toput);
- toput = NULL;
- if (dentry != result &&
- acceptable(context, dentry)) {
- dput(result);
- return dentry;
- }
- spin_lock(&dcache_lock);
- toput = dentry;
- }
- spin_unlock(&dcache_lock);
- if (toput)
- dput(toput);
+
+ alias = find_acceptable_alias(result, acceptable, context);
+ if (alias)
+ return alias;
}
/* It's a directory, or we are required to confirm the file's
if (!IS_ROOT(pd)) {
/* must have found a connected parent - great */
+ spin_lock(&pd->d_lock);
pd->d_flags &= ~DCACHE_DISCONNECTED;
+ spin_unlock(&pd->d_lock);
noprogress = 0;
} else if (pd == sb->s_root) {
printk(KERN_ERR "export: Eeek filesystem root is not connected, impossible\n");
+ spin_lock(&pd->d_lock);
pd->d_flags &= ~DCACHE_DISCONNECTED;
+ spin_unlock(&pd->d_lock);
noprogress = 0;
} else {
/* we have hit the top of a disconnected path. Try
*/
struct dentry *ppd;
struct dentry *npd;
- char nbuf[NAME_MAX+1];
- down(&pd->d_inode->i_sem);
+ mutex_lock(&pd->d_inode->i_mutex);
ppd = CALL(nops,get_parent)(pd);
- up(&pd->d_inode->i_sem);
+ mutex_unlock(&pd->d_inode->i_mutex);
if (IS_ERR(ppd)) {
err = PTR_ERR(ppd);
break;
}
dprintk("find_exported_dentry: found name: %s\n", nbuf);
- down(&ppd->d_inode->i_sem);
+ mutex_lock(&ppd->d_inode->i_mutex);
npd = lookup_one_len(nbuf, ppd, strlen(nbuf));
- up(&ppd->d_inode->i_sem);
+ mutex_unlock(&ppd->d_inode->i_mutex);
if (IS_ERR(npd)) {
err = PTR_ERR(npd);
dprintk("find_exported_dentry: lookup failed: %d\n", err);
/* if we weren't after a directory, have one more step to go */
if (result != target_dir) {
struct dentry *nresult;
- char nbuf[NAME_MAX+1];
err = CALL(nops,get_name)(target_dir, nbuf, result);
if (!err) {
- down(&target_dir->d_inode->i_sem);
+ mutex_lock(&target_dir->d_inode->i_mutex);
nresult = lookup_one_len(nbuf, target_dir, strlen(nbuf));
- up(&target_dir->d_inode->i_sem);
+ mutex_unlock(&target_dir->d_inode->i_mutex);
if (!IS_ERR(nresult)) {
if (nresult->d_inode) {
dput(result);
/* now result is properly connected, it is our best bet */
if (acceptable(context, result))
return result;
- /* one last try of the aliases.. */
- spin_lock(&dcache_lock);
- toput = NULL;
- head = &result->d_inode->i_dentry;
- list_for_each(le, head) {
- struct dentry *dentry = list_entry(le, struct dentry, d_alias);
- dget_locked(dentry);
- spin_unlock(&dcache_lock);
- if (toput) dput(toput);
- if (dentry != result &&
- acceptable(context, dentry)) {
- dput(result);
- return dentry;
- }
- spin_lock(&dcache_lock);
- toput = dentry;
- }
- spin_unlock(&dcache_lock);
- if (toput)
- dput(toput);
+
+ alias = find_acceptable_alias(result, acceptable, context);
+ if (alias)
+ return alias;
/* drat - I just cannot find anything acceptable */
dput(result);
- return ERR_PTR(-ESTALE);
+ /* It might be justifiable to return ESTALE here,
+ * but the filehandle at-least looks reasonable good
+ * and it just be a permission problem, so returning
+ * -EACCESS is safer
+ */
+ return ERR_PTR(-EACCES);
err_target:
dput(target_dir);
{
struct inode *dir = dentry->d_inode;
int error;
- struct file file;
+ struct file *file;
struct getdents_callback buffer;
error = -ENOTDIR;
/*
* Open the directory ...
*/
- error = open_private_file(&file, dentry, O_RDONLY);
- if (error)
+ file = dentry_open(dget(dentry), NULL, O_RDONLY);
+ error = PTR_ERR(file);
+ if (IS_ERR(file))
goto out;
+
error = -EINVAL;
- if (!file.f_op->readdir)
+ if (!file->f_op->readdir)
goto out_close;
buffer.name = name;
while (1) {
int old_seq = buffer.sequence;
- error = vfs_readdir(&file, filldir_one, &buffer);
+ error = vfs_readdir(file, filldir_one, &buffer);
if (error < 0)
break;
}
out_close:
- close_private_file(&file);
+ fput(file);
out:
return error;
}