Commit 5e993e25 authored by Al Viro's avatar Al Viro

ncpfs: get rid of d_validate() nonsense

What we want is to have non-counting references to children in
pagecache of parent directory, and avoid picking them after a child
has been freed.  Fine, so let's just have ->d_prune() clear
parent's inode "has directory contents in page cache" flag.
That way we don't need ->d_fsdata for storing offsets, so we can
use it as a quick and dirty "is it referenced from page cache"
flag.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent ad52184b
...@@ -77,6 +77,7 @@ static int ncp_hash_dentry(const struct dentry *, struct qstr *); ...@@ -77,6 +77,7 @@ static int ncp_hash_dentry(const struct dentry *, struct qstr *);
static int ncp_compare_dentry(const struct dentry *, const struct dentry *, static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
unsigned int, const char *, const struct qstr *); unsigned int, const char *, const struct qstr *);
static int ncp_delete_dentry(const struct dentry *); static int ncp_delete_dentry(const struct dentry *);
static void ncp_d_prune(struct dentry *dentry);
const struct dentry_operations ncp_dentry_operations = const struct dentry_operations ncp_dentry_operations =
{ {
...@@ -84,6 +85,7 @@ const struct dentry_operations ncp_dentry_operations = ...@@ -84,6 +85,7 @@ const struct dentry_operations ncp_dentry_operations =
.d_hash = ncp_hash_dentry, .d_hash = ncp_hash_dentry,
.d_compare = ncp_compare_dentry, .d_compare = ncp_compare_dentry,
.d_delete = ncp_delete_dentry, .d_delete = ncp_delete_dentry,
.d_prune = ncp_d_prune,
}; };
#define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber]) #define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
...@@ -384,42 +386,6 @@ ncp_lookup_validate(struct dentry *dentry, unsigned int flags) ...@@ -384,42 +386,6 @@ ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
return val; return val;
} }
static struct dentry *
ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
{
struct dentry *dent = dentry;
if (d_validate(dent, parent)) {
if (dent->d_name.len <= NCP_MAXPATHLEN &&
(unsigned long)dent->d_fsdata == fpos) {
if (!dent->d_inode) {
dput(dent);
dent = NULL;
}
return dent;
}
dput(dent);
}
/* If a pointer is invalid, we search the dentry. */
spin_lock(&parent->d_lock);
list_for_each_entry(dent, &parent->d_subdirs, d_child) {
if ((unsigned long)dent->d_fsdata == fpos) {
if (dent->d_inode)
dget(dent);
else
dent = NULL;
spin_unlock(&parent->d_lock);
goto out;
}
}
spin_unlock(&parent->d_lock);
return NULL;
out:
return dent;
}
static time_t ncp_obtain_mtime(struct dentry *dentry) static time_t ncp_obtain_mtime(struct dentry *dentry)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
...@@ -435,6 +401,20 @@ static time_t ncp_obtain_mtime(struct dentry *dentry) ...@@ -435,6 +401,20 @@ static time_t ncp_obtain_mtime(struct dentry *dentry)
return ncp_date_dos2unix(i.modifyTime, i.modifyDate); return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
} }
static inline void
ncp_invalidate_dircache_entries(struct dentry *parent)
{
struct ncp_server *server = NCP_SERVER(parent->d_inode);
struct dentry *dentry;
spin_lock(&parent->d_lock);
list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
dentry->d_fsdata = NULL;
ncp_age_dentry(server, dentry);
}
spin_unlock(&parent->d_lock);
}
static int ncp_readdir(struct file *file, struct dir_context *ctx) static int ncp_readdir(struct file *file, struct dir_context *ctx)
{ {
struct dentry *dentry = file->f_path.dentry; struct dentry *dentry = file->f_path.dentry;
...@@ -500,10 +480,21 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx) ...@@ -500,10 +480,21 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx)
struct dentry *dent; struct dentry *dent;
bool over; bool over;
dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx], spin_lock(&dentry->d_lock);
dentry, ctx->pos); if (!(NCP_FINFO(inode)->flags & NCPI_DIR_CACHE)) {
if (!dent) spin_unlock(&dentry->d_lock);
goto invalid_cache;
}
dent = ctl.cache->dentry[ctl.idx];
if (unlikely(!lockref_get_not_dead(&dent->d_lockref))) {
spin_unlock(&dentry->d_lock);
goto invalid_cache;
}
spin_unlock(&dentry->d_lock);
if (!dent->d_inode) {
dput(dent);
goto invalid_cache; goto invalid_cache;
}
over = !dir_emit(ctx, dent->d_name.name, over = !dir_emit(ctx, dent->d_name.name,
dent->d_name.len, dent->d_name.len,
dent->d_inode->i_ino, DT_UNKNOWN); dent->d_inode->i_ino, DT_UNKNOWN);
...@@ -548,6 +539,9 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx) ...@@ -548,6 +539,9 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx)
ctl.filled = 0; ctl.filled = 0;
ctl.valid = 1; ctl.valid = 1;
read_really: read_really:
spin_lock(&dentry->d_lock);
NCP_FINFO(inode)->flags |= NCPI_DIR_CACHE;
spin_unlock(&dentry->d_lock);
if (ncp_is_server_root(inode)) { if (ncp_is_server_root(inode)) {
ncp_read_volume_list(file, ctx, &ctl); ncp_read_volume_list(file, ctx, &ctl);
} else { } else {
...@@ -573,6 +567,13 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx) ...@@ -573,6 +567,13 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx)
return result; return result;
} }
static void ncp_d_prune(struct dentry *dentry)
{
if (!dentry->d_fsdata) /* not referenced from page cache */
return;
NCP_FINFO(dentry->d_parent->d_inode)->flags &= ~NCPI_DIR_CACHE;
}
static int static int
ncp_fill_cache(struct file *file, struct dir_context *ctx, ncp_fill_cache(struct file *file, struct dir_context *ctx,
struct ncp_cache_control *ctrl, struct ncp_entry_info *entry, struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
...@@ -630,6 +631,10 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, ...@@ -630,6 +631,10 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx,
d_instantiate(newdent, inode); d_instantiate(newdent, inode);
if (!hashed) if (!hashed)
d_rehash(newdent); d_rehash(newdent);
} else {
spin_lock(&dentry->d_lock);
NCP_FINFO(inode)->flags &= ~NCPI_DIR_CACHE;
spin_unlock(&dentry->d_lock);
} }
} else { } else {
struct inode *inode = newdent->d_inode; struct inode *inode = newdent->d_inode;
...@@ -639,12 +644,6 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, ...@@ -639,12 +644,6 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx,
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
} }
if (newdent->d_inode) {
ino = newdent->d_inode->i_ino;
newdent->d_fsdata = (void *) ctl.fpos;
ncp_new_dentry(newdent);
}
if (ctl.idx >= NCP_DIRCACHE_SIZE) { if (ctl.idx >= NCP_DIRCACHE_SIZE) {
if (ctl.page) { if (ctl.page) {
kunmap(ctl.page); kunmap(ctl.page);
...@@ -660,8 +659,13 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, ...@@ -660,8 +659,13 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx,
ctl.cache = kmap(ctl.page); ctl.cache = kmap(ctl.page);
} }
if (ctl.cache) { if (ctl.cache) {
ctl.cache->dentry[ctl.idx] = newdent; if (newdent->d_inode) {
valid = 1; newdent->d_fsdata = newdent;
ctl.cache->dentry[ctl.idx] = newdent;
ino = newdent->d_inode->i_ino;
ncp_new_dentry(newdent);
}
valid = 1;
} }
dput(newdent); dput(newdent);
end_advance: end_advance:
......
...@@ -22,6 +22,7 @@ struct ncp_inode_info { ...@@ -22,6 +22,7 @@ struct ncp_inode_info {
int access; int access;
int flags; int flags;
#define NCPI_KLUDGE_SYMLINK 0x0001 #define NCPI_KLUDGE_SYMLINK 0x0001
#define NCPI_DIR_CACHE 0x0002
__u8 file_handle[6]; __u8 file_handle[6];
struct inode vfs_inode; struct inode vfs_inode;
}; };
......
...@@ -184,36 +184,6 @@ ncp_new_dentry(struct dentry* dentry) ...@@ -184,36 +184,6 @@ ncp_new_dentry(struct dentry* dentry)
dentry->d_time = jiffies; dentry->d_time = jiffies;
} }
static inline void
ncp_renew_dentries(struct dentry *parent)
{
struct ncp_server *server = NCP_SERVER(parent->d_inode);
struct dentry *dentry;
spin_lock(&parent->d_lock);
list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
if (dentry->d_fsdata == NULL)
ncp_age_dentry(server, dentry);
else
ncp_new_dentry(dentry);
}
spin_unlock(&parent->d_lock);
}
static inline void
ncp_invalidate_dircache_entries(struct dentry *parent)
{
struct ncp_server *server = NCP_SERVER(parent->d_inode);
struct dentry *dentry;
spin_lock(&parent->d_lock);
list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
dentry->d_fsdata = NULL;
ncp_age_dentry(server, dentry);
}
spin_unlock(&parent->d_lock);
}
struct ncp_cache_head { struct ncp_cache_head {
time_t mtime; time_t mtime;
unsigned long time; /* cache age */ unsigned long time; /* cache age */
......
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