EXIT;
}
+/* Drop dentry if it is not used already, unhash otherwise.
+ Should be called with dcache lock held!
+ Returns: 1 if dentry was dropped, 0 if unhashed. */
+int ll_drop_dentry(struct dentry *dentry)
+{
+ lock_dentry(dentry);
+ CDEBUG(D_DENTRY, "dentry in drop %.*s (%p) parent %p "
+ "inode %p flags %d\n", dentry->d_name.len,
+ dentry->d_name.name, dentry, dentry->d_parent,
+ dentry->d_inode, dentry->d_flags);
+
+ if (atomic_read(&dentry->d_count) == 0) {
+ CDEBUG(D_DENTRY, "deleting dentry %.*s (%p) parent %p "
+ "inode %p\n", dentry->d_name.len,
+ dentry->d_name.name, dentry, dentry->d_parent,
+ dentry->d_inode);
+ dget_locked(dentry);
+ __d_drop(dentry);
+ unlock_dentry(dentry);
+ spin_unlock(&dcache_lock);
+ dput(dentry);
+ spin_lock(&dcache_lock);
+ return 1;
+ }
+
+#ifdef LUSTRE_KERNEL_VERSION
+ if (!(dentry->d_flags & DCACHE_LUSTRE_INVALID)) {
+#else
+ if (!d_unhashed(dentry)) {
+ struct inode *inode = dentry->d_inode;
+#endif
+ CDEBUG(D_DENTRY, "unhashing dentry %.*s (%p) parent %p "
+ "inode %p refc %d\n", dentry->d_name.len,
+ dentry->d_name.name, dentry, dentry->d_parent,
+ dentry->d_inode, atomic_read(&dentry->d_count));
+ /* actually we don't unhash the dentry, rather just
+ * mark it inaccessible for to __d_lookup(). otherwise
+ * sys_getcwd() could return -ENOENT -bzzz */
+#ifdef LUSTRE_KERNEL_VERSION
+ dentry->d_flags |= DCACHE_LUSTRE_INVALID;
+#else
+ if (!inode || !S_ISDIR(inode->i_mode))
+ __d_drop(dentry);
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+ __d_drop(dentry);
+ if (inode) {
+ /* Put positive dentries to orphan list */
+ hlist_add_head(&dentry->d_hash,
+ &ll_i2sbi(inode)->ll_orphan_dentry_list);
+ }
+#endif
+ }
+ unlock_dentry(dentry);
+ return 0;
+}
+
void ll_unhash_aliases(struct inode *inode)
{
struct list_head *tmp, *head;
return;
}
- CDEBUG(D_INODE, "marking dentries for ino %lu/%u(%p) invalid\n",
+ CDEBUG(D_INODE, "marking dentries for 111 ino %lu/%u(%p) invalid\n",
inode->i_ino, inode->i_generation, inode);
head = &inode->i_dentry;
-restart:
spin_lock(&dcache_lock);
+restart:
tmp = head;
while ((tmp = tmp->next) != head) {
struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
+ CDEBUG(D_DENTRY, "dentry in drop %.*s (%p) parent %p "
+ "inode %p flags %d\n", dentry->d_name.len,
+ dentry->d_name.name, dentry, dentry->d_parent,
+ dentry->d_inode, dentry->d_flags);
+
if (dentry->d_name.len == 1 && dentry->d_name.name[0] == '/') {
CERROR("called on root (?) dentry=%p, inode=%p "
"ino=%lu\n", dentry, inode, inode->i_ino);
continue;
}
-
- lock_dentry(dentry);
- if (atomic_read(&dentry->d_count) == 0) {
- CDEBUG(D_DENTRY, "deleting dentry %.*s (%p) parent %p "
- "inode %p\n", dentry->d_name.len,
- dentry->d_name.name, dentry, dentry->d_parent,
- dentry->d_inode);
- dget_locked(dentry);
- __d_drop(dentry);
- unlock_dentry(dentry);
- spin_unlock(&dcache_lock);
- dput(dentry);
- goto restart;
- } else if (!(dentry->d_flags & DCACHE_LUSTRE_INVALID)) {
- CDEBUG(D_DENTRY, "unhashing dentry %.*s (%p) parent %p "
- "inode %p refc %d\n", dentry->d_name.len,
- dentry->d_name.name, dentry, dentry->d_parent,
- dentry->d_inode, atomic_read(&dentry->d_count));
- /* actually we don't unhash the dentry, rather just
- * mark it inaccessible for to __d_lookup(). otherwise
- * sys_getcwd() could return -ENOENT -bzzz */
- dentry->d_flags |= DCACHE_LUSTRE_INVALID;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
- __d_drop(dentry);
- hlist_add_head(&dentry->d_hash,
- &ll_i2sbi(inode)->ll_orphan_dentry_list);
-#endif
- }
- unlock_dentry(dentry);
+
+ if (ll_drop_dentry(dentry))
+ goto restart;
}
spin_unlock(&dcache_lock);
EXIT;
RETURN(rc);
}
+int ll_have_md_lock(struct inode *inode, __u64 bits)
+{
+ struct lustre_handle lockh;
+ ldlm_policy_data_t policy = { .l_inodebits = {bits}};
+ struct lu_fid *fid;
+ int flags;
+ ENTRY;
+
+ if (!inode)
+ RETURN(0);
+
+ fid = &ll_i2info(inode)->lli_fid;
+ CDEBUG(D_INFO, "trying to match res "DFID3"\n", PFID3(fid));
+
+ flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK;
+ if (md_lock_match(ll_i2mdexp(inode), flags, fid, LDLM_IBITS, &policy,
+ LCK_CR|LCK_CW|LCK_PR, &lockh)) {
+ RETURN(1);
+ }
+
+ RETURN(0);
+}
+
int ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it)
{
struct lookup_intent oit = { .it_op = IT_GETATTR };
rc = ll_revalidate_it_finish(req, 1, &oit, dentry);
if (rc)
GOTO(out, rc);
-
+
+ if (!dentry->d_inode->i_nlink) {
+ spin_lock(&dcache_lock);
+ ll_drop_dentry(dentry);
+ spin_unlock(&dcache_lock);
+ }
+
ll_lookup_finish_locks(&oit, dentry);
/* object is allocated, validate size */
# include <linux/pagemap.h>
# include <linux/miscdevice.h>
# include <linux/init.h>
-#include <linux/lustre_acl.h>
#else
# include <liblustre.h>
#endif
+#include <linux/lustre_acl.h>
#include <obd_class.h>
#include <lustre_dlm.h>
#include <lprocfs_status.h>
sizeof(lockh));
it->d.lustre.it_lock_mode = mode;
}
- RETURN(rc);
+
+ if (rc || op_data->namelen != 0)
+ RETURN(rc);
}
/* lookup_it may be called only after revalidate_it has run, because
/* If we were revalidating a fid/name pair, mark the intent in
* case we fail and get called again from lookup */
if (fid_is_sane(&op_data->fid2) &&
- !it_disposition(it, DISP_OPEN_CREATE)) {
+ !it_disposition(it, DISP_OPEN_CREATE) &&
+ !(it->it_op & IT_GETATTR)) {
it_set_disposition(it, DISP_ENQ_COMPLETE);
/* Also: did we find the same inode? */
- if (!((it->it_create_mode & O_CREAT) || it->it_op & IT_CREAT)
+ if (!(it->it_create_mode & O_CREAT || it->it_op & IT_CREAT)
&& memcmp(&op_data->fid2, &mdt_body->fid1,
sizeof(op_data->fid2)))
RETURN(-ESTALE);