static struct dentry *get_next_positive_subdir(struct dentry *prev, struct dentry *root) { struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb); struct list_head *next; struct dentry *p, *q; spin_lock(&sbi->lookup_lock); if (prev == NULL) { spin_lock(&root->d_lock); prev = dget_dlock(root); next = prev->d_subdirs.next; p = prev; goto start; } p = prev; spin_lock(&p->d_lock); again: next = p->d_u.d_child.next; start: if (next == &root->d_subdirs) { spin_unlock(&p->d_lock); spin_unlock(&sbi->lookup_lock); dput(prev); return NULL; } q = list_entry(next, struct dentry, d_u.d_child); spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED); if (!simple_positive(q)) { spin_unlock(&p->d_lock); lock_set_subclass(&q->d_lock.dep_map, 0, _RET_IP_); p = q; goto again; } dget_dlock(q); spin_unlock(&q->d_lock); spin_unlock(&p->d_lock); spin_unlock(&sbi->lookup_lock); dput(prev); return q; }
static void sel_remove_entries(struct dentry *de) { struct list_head *node; spin_lock(&de->d_lock); node = de->d_subdirs.next; while (node != &de->d_subdirs) { struct dentry *d = list_entry(node, struct dentry, d_u.d_child); spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); list_del_init(node); if (d->d_inode) { dget_dlock(d); spin_unlock(&de->d_lock); spin_unlock(&d->d_lock); d_delete(d); simple_unlink(de->d_inode, d); dput(d); spin_lock(&de->d_lock); } else spin_unlock(&d->d_lock); node = de->d_subdirs.next; } spin_unlock(&de->d_lock); }
static int remove_file(struct dentry *parent, char *name) { struct dentry *tmp; int ret; tmp = lookup_one_len(name, parent, strlen(name)); if (IS_ERR(tmp)) { ret = PTR_ERR(tmp); goto bail; } spin_lock(&tmp->d_lock); if (!(d_unhashed(tmp) && tmp->d_inode)) { dget_dlock(tmp); __d_drop(tmp); spin_unlock(&tmp->d_lock); simple_unlink(parent->d_inode, tmp); } else spin_unlock(&tmp->d_lock); ret = 0; bail: /* * We don't expect clients to care about the return value, but * it's there if they need it. */ return ret; }
/* * Calculate and dget next entry in top down tree traversal. */ static struct dentry *get_next_positive_dentry(struct dentry *prev, struct dentry *root) { struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb); struct list_head *next; struct dentry *p, *ret; if (prev == NULL) return dget(root); spin_lock(&sbi->lookup_lock); relock: p = prev; spin_lock(&p->d_lock); again: next = p->d_subdirs.next; if (next == &p->d_subdirs) { while (1) { struct dentry *parent; if (p == root) { spin_unlock(&p->d_lock); spin_unlock(&sbi->lookup_lock); dput(prev); return NULL; } parent = p->d_parent; if (!spin_trylock(&parent->d_lock)) { spin_unlock(&p->d_lock); cpu_relax(); goto relock; } spin_unlock(&p->d_lock); next = p->d_child.next; p = parent; if (next != &parent->d_subdirs) break; } } ret = list_entry(next, struct dentry, d_child); spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED); /* Negative dentry - try next */ if (!simple_positive(ret)) { spin_unlock(&p->d_lock); lock_set_subclass(&ret->d_lock.dep_map, 0, _RET_IP_); p = ret; goto again; } dget_dlock(ret); spin_unlock(&ret->d_lock); spin_unlock(&p->d_lock); spin_unlock(&sbi->lookup_lock); dput(prev); return ret; }
/* * Calculate and dget next entry in the subdirs list under root. */ static struct dentry *get_next_positive_subdir(struct dentry *prev, struct dentry *root) { struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb); struct list_head *next; struct dentry *q; spin_lock(&sbi->lookup_lock); spin_lock(&root->d_lock); if (prev) next = prev->d_child.next; else { prev = dget_dlock(root); next = prev->d_subdirs.next; } cont: if (next == &root->d_subdirs) { spin_unlock(&root->d_lock); spin_unlock(&sbi->lookup_lock); dput(prev); return NULL; } q = list_entry(next, struct dentry, d_child); spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED); /* Already gone or negative dentry (under construction) - try next */ if (!d_count(q) || !simple_positive(q)) { spin_unlock(&q->d_lock); next = q->d_child.next; goto cont; } dget_dlock(q); spin_unlock(&q->d_lock); spin_unlock(&root->d_lock); spin_unlock(&sbi->lookup_lock); dput(prev); return q; }
static int remove_file(struct dentry *parent, char *name) { struct dentry *tmp; int ret; tmp = lookup_one_len(name, parent, strlen(name)); if (IS_ERR(tmp)) { ret = PTR_ERR(tmp); goto bail; } #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)) spin_lock(&dcache_lock); #endif spin_lock(&tmp->d_lock); if (!(d_unhashed(tmp) && tmp->d_inode)) { #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)) dget_locked(tmp); #else dget_dlock(tmp); #endif __d_drop(tmp); spin_unlock(&tmp->d_lock); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)) spin_unlock(&dcache_lock); #endif simple_unlink(parent->d_inode, tmp); } else { spin_unlock(&tmp->d_lock); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)) spin_unlock(&dcache_lock); #endif } ret = 0; bail: /* * We don't expect clients to care about the return value, but * it's there if they need it. */ return ret; }
static int au_dpages_append(struct au_dcsub_pages *dpages, struct dentry *dentry, gfp_t gfp) { int err, sz; struct au_dpage *dpage; void *p; dpage = dpages->dpages + dpages->ndpage - 1; sz = PAGE_SIZE / sizeof(dentry); if (unlikely(dpage->ndentry >= sz)) { AuLabel(new dpage); err = -ENOMEM; sz = dpages->ndpage * sizeof(*dpages->dpages); p = au_kzrealloc(dpages->dpages, sz, sz + sizeof(*dpages->dpages), gfp); if (unlikely(!p)) goto out; dpages->dpages = p; dpage = dpages->dpages + dpages->ndpage; p = (void *)__get_free_page(gfp); if (unlikely(!p)) goto out; dpage->ndentry = 0; dpage->dentries = p; dpages->ndpage++; } AuDebugOn(!d_count(dentry)); dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); return 0; /* success */ out: return err; }