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 (simple_positive(tmp)) { dget_dlock(tmp); __d_drop(tmp); spin_unlock(&tmp->d_lock); simple_unlink(d_inode(parent), 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; }
static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, struct dentry *parent, unsigned long timeout, int do_now) { struct dentry *this_parent = parent; struct list_head *next; DPRINTK("parent %p %.*s", parent, (int)parent->d_name.len, parent->d_name.name); spin_lock(&dcache_lock); repeat: next = this_parent->d_subdirs.next; resume: while (next != &this_parent->d_subdirs) { struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); /* Negative dentry - give up */ if (!simple_positive(dentry)) { next = next->next; continue; } DPRINTK("dentry %p %.*s", dentry, (int)dentry->d_name.len, dentry->d_name.name); if (!list_empty(&dentry->d_subdirs)) { this_parent = dentry; goto repeat; } dentry = dget(dentry); spin_unlock(&dcache_lock); if (d_mountpoint(dentry)) { /* Can we expire this guy */ if (!autofs4_can_expire(dentry, timeout, do_now)) goto cont; /* Can we umount this guy */ if (autofs4_check_mount(mnt, dentry)) return dentry; } cont: dput(dentry); spin_lock(&dcache_lock); next = next->next; } if (this_parent != parent) { next = this_parent->d_u.d_child.next; this_parent = this_parent->d_parent; goto resume; } spin_unlock(&dcache_lock); return NULL; }
/* * 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; }
/* * Check a directory tree of mount points for busyness * The tree is not busy iff no mountpoints are busy */ static int autofs4_tree_busy(struct vfsmount *mnt, struct dentry *top, unsigned long timeout, int do_now) { struct autofs_info *top_ino = autofs4_dentry_ino(top); struct dentry *p; pr_debug("top %p %pd\n", top, top); /* Negative dentry - give up */ if (!simple_positive(top)) return 1; p = NULL; while ((p = get_next_positive_dentry(p, top))) { pr_debug("dentry %p %pd\n", p, p); /* * Is someone visiting anywhere in the subtree ? * If there's no mount we need to check the usage * count for the autofs dentry. * If the fs is busy update the expiry counter. */ if (d_mountpoint(p)) { if (autofs4_mount_busy(mnt, p)) { top_ino->last_used = jiffies; dput(p); return 1; } } else { struct autofs_info *ino = autofs4_dentry_ino(p); unsigned int ino_count = atomic_read(&ino->count); /* allow for dget above and top is already dgot */ if (p == top) ino_count += 2; else ino_count++; if (d_count(p) > ino_count) { top_ino->last_used = jiffies; dput(p); return 1; } } } /* Timeout of a tree mount is ultimately determined by its top dentry */ if (!autofs4_can_expire(top, timeout, do_now)) return 1; return 0; }
/* * Deal with the infamous "Busy inodes after umount ..." message. * * Clean up the dentry tree. This happens with autofs if the user * space program goes away due to a SIGKILL, SIGSEGV etc. */ static void autofs4_force_release(struct autofs_sb_info *sbi) { struct dentry *this_parent = sbi->sb->s_root; struct list_head *next; if (!sbi->sb->s_root) return; spin_lock(&dcache_lock); repeat: next = this_parent->d_subdirs.next; resume: while (next != &this_parent->d_subdirs) { struct dentry *dentry = list_entry(next, struct dentry, d_child); /* Negative dentry - don`t care */ if (!simple_positive(dentry)) { next = next->next; continue; } if (!list_empty(&dentry->d_subdirs)) { this_parent = dentry; goto repeat; } next = next->next; spin_unlock(&dcache_lock); DPRINTK("dentry %p %.*s", dentry, (int)dentry->d_name.len, dentry->d_name.name); dput(dentry); spin_lock(&dcache_lock); } if (this_parent != sbi->sb->s_root) { struct dentry *dentry = this_parent; next = this_parent->d_child.next; this_parent = this_parent->d_parent; spin_unlock(&dcache_lock); DPRINTK("parent dentry %p %.*s", dentry, (int)dentry->d_name.len, dentry->d_name.name); dput(dentry); spin_lock(&dcache_lock); goto resume; } spin_unlock(&dcache_lock); shrink_dcache_sb(sbi->sb); return; }
static int autofs4_tree_busy(struct vfsmount *mnt, struct dentry *top, unsigned long timeout, int do_now) { struct autofs_info *top_ino = autofs4_dentry_ino(top); struct dentry *p; DPRINTK("top %p %.*s", top, (int)top->d_name.len, top->d_name.name); if (!simple_positive(top)) return 1; p = NULL; while ((p = get_next_positive_dentry(p, top))) { DPRINTK("dentry %p %.*s", p, (int) p->d_name.len, p->d_name.name); if (d_mountpoint(p)) { if (autofs4_mount_busy(mnt, p)) { top_ino->last_used = jiffies; dput(p); return 1; } } else { struct autofs_info *ino = autofs4_dentry_ino(p); unsigned int ino_count = atomic_read(&ino->count); d_invalidate(p); if (p == top) ino_count += 2; else ino_count++; if (p->d_count > ino_count) { top_ino->last_used = jiffies; dput(p); return 1; } } } if (!autofs4_can_expire(top, timeout, do_now)) return 1; return 0; }
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 hypfs_remove(struct dentry *dentry) { struct dentry *parent; parent = dentry->d_parent; inode_lock(d_inode(parent)); if (simple_positive(dentry)) { if (d_is_dir(dentry)) simple_rmdir(d_inode(parent), dentry); else simple_unlink(d_inode(parent), dentry); } d_delete(dentry); dput(dentry); inode_unlock(d_inode(parent)); }
/** * securityfs_remove - removes a file or directory from the securityfs filesystem * * @dentry: a pointer to a the dentry of the file or directory to be removed. * * This function removes a file or directory in securityfs that was previously * created with a call to another securityfs function (like * securityfs_create_file() or variants thereof.) * * This function is required to be called in order for the file to be * removed. No automatic cleanup of files will happen when a module is * removed; you are responsible here. */ void securityfs_remove(struct dentry *dentry) { struct inode *dir; if (!dentry || IS_ERR(dentry)) return; dir = d_inode(dentry->d_parent); inode_lock(dir); if (simple_positive(dentry)) { if (d_is_dir(dentry)) simple_rmdir(dir, dentry); else simple_unlink(dir, dentry); dput(dentry); } inode_unlock(dir); simple_release_fs(&mount, &mount_count); }
/* * 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; }
/** * securityfs_remove - removes a file or directory from the securityfs filesystem * * @dentry: a pointer to a the dentry of the file or directory to be removed. * * This function removes a file or directory in securityfs that was previously * created with a call to another securityfs function (like * securityfs_create_file() or variants thereof.) * * This function is required to be called in order for the file to be * removed. No automatic cleanup of files will happen when a module is * removed; you are responsible here. */ void securityfs_remove(struct dentry *dentry) { struct dentry *parent; if (!dentry || IS_ERR(dentry)) return; parent = dentry->d_parent; if (!parent || d_really_is_negative(parent)) return; inode_lock(d_inode(parent)); if (simple_positive(dentry)) { if (d_is_dir(dentry)) simple_rmdir(d_inode(parent), dentry); else simple_unlink(d_inode(parent), dentry); dput(dentry); } inode_unlock(d_inode(parent)); simple_release_fs(&mount, &mount_count); }
loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence) { struct dentry *dentry = file->f_path.dentry; mutex_lock(&dentry->d_inode->i_mutex); switch (whence) { case 1: offset += file->f_pos; case 0: if (offset >= 0) break; default: mutex_unlock(&dentry->d_inode->i_mutex); return -EINVAL; } if (offset != file->f_pos) { file->f_pos = offset; if (file->f_pos >= 2) { struct list_head *p; struct dentry *cursor = file->private_data; loff_t n = file->f_pos - 2; spin_lock(&dentry->d_lock); /* d_lock not required for cursor */ list_del(&cursor->d_u.d_child); p = dentry->d_subdirs.next; while (n && p != &dentry->d_subdirs) { struct dentry *next; next = list_entry(p, struct dentry, d_u.d_child); spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); if (simple_positive(next)) n--; spin_unlock(&next->d_lock); p = p->next; } list_add_tail(&cursor->d_u.d_child, p); spin_unlock(&dentry->d_lock); } }
static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, struct dentry *parent, unsigned long timeout, int do_now) { struct dentry *p; DPRINTK("parent %p %.*s", parent, (int)parent->d_name.len, parent->d_name.name); spin_lock(&dcache_lock); for (p = parent; p; p = next_dentry(p, parent)) { /* Negative dentry - give up */ if (!simple_positive(p)) continue; DPRINTK("dentry %p %.*s", p, (int) p->d_name.len, p->d_name.name); p = dget(p); spin_unlock(&dcache_lock); if (d_mountpoint(p)) { /* Can we umount this guy */ if (autofs4_mount_busy(mnt, p)) goto cont; /* Can we expire this guy */ if (autofs4_can_expire(p, timeout, do_now)) return p; } cont: dput(p); spin_lock(&dcache_lock); } spin_unlock(&dcache_lock); return NULL; }
/* Check a directory tree of mount points for busyness * The tree is not busy iff no mountpoints are busy * Return 1 if the tree is busy or 0 otherwise */ static int autofs4_check_tree(struct vfsmount *mnt, struct dentry *top, unsigned long timeout, int do_now) { struct dentry *this_parent = top; struct list_head *next; DPRINTK("parent %p %.*s", top, (int)top->d_name.len, top->d_name.name); /* Negative dentry - give up */ if (!simple_positive(top)) return 0; /* Timeout of a tree mount is determined by its top dentry */ if (!autofs4_can_expire(top, timeout, do_now)) return 0; /* Is someone visiting anywhere in the tree ? */ if (may_umount_tree(mnt)) return 0; spin_lock(&dcache_lock); repeat: next = this_parent->d_subdirs.next; resume: while (next != &this_parent->d_subdirs) { struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); /* Negative dentry - give up */ if (!simple_positive(dentry)) { next = next->next; continue; } DPRINTK("dentry %p %.*s", dentry, (int)dentry->d_name.len, dentry->d_name.name); if (!simple_empty_nolock(dentry)) { this_parent = dentry; goto repeat; } dentry = dget(dentry); spin_unlock(&dcache_lock); if (d_mountpoint(dentry)) { /* First busy => tree busy */ if (!autofs4_check_mount(mnt, dentry)) { dput(dentry); return 0; } } dput(dentry); spin_lock(&dcache_lock); next = next->next; } if (this_parent != top) { next = this_parent->d_u.d_child.next; this_parent = this_parent->d_parent; goto resume; } spin_unlock(&dcache_lock); return 1; }
/* * Find an eligible tree to time-out * A tree is eligible if :- * - it is unused by any user process * - it has been unused for exp_timeout time */ static struct dentry *autofs4_expire(struct super_block *sb, struct vfsmount *mnt, struct autofs_sb_info *sbi, int how) { unsigned long timeout; struct dentry *root = sb->s_root; struct dentry *expired = NULL; struct list_head *next; int do_now = how & AUTOFS_EXP_IMMEDIATE; int exp_leaves = how & AUTOFS_EXP_LEAVES; if ( !sbi->exp_timeout || !root ) return NULL; now = jiffies; timeout = sbi->exp_timeout; spin_lock(&dcache_lock); next = root->d_subdirs.next; /* On exit from the loop expire is set to a dgot dentry * to expire or it's NULL */ while ( next != &root->d_subdirs ) { struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); /* Negative dentry - give up */ if ( !simple_positive(dentry) ) { next = next->next; continue; } dentry = dget(dentry); spin_unlock(&dcache_lock); /* Case 1: indirect mount or top level direct mount */ if (d_mountpoint(dentry)) { DPRINTK("checking mountpoint %p %.*s", dentry, (int)dentry->d_name.len, dentry->d_name.name); /* Can we expire this guy */ if (!autofs4_can_expire(dentry, timeout, do_now)) goto next; /* Can we umount this guy */ if (autofs4_check_mount(mnt, dentry)) { expired = dentry; break; } goto next; } if ( simple_empty(dentry) ) goto next; /* Case 2: tree mount, expire iff entire tree is not busy */ if (!exp_leaves) { /* Lock the tree as we must expire as a whole */ spin_lock(&sbi->fs_lock); if (autofs4_check_tree(mnt, dentry, timeout, do_now)) { struct autofs_info *inf = autofs4_dentry_ino(dentry); /* Set this flag early to catch sys_chdir and the like */ inf->flags |= AUTOFS_INF_EXPIRING; spin_unlock(&sbi->fs_lock); expired = dentry; break; } spin_unlock(&sbi->fs_lock); /* Case 3: direct mount, expire individual leaves */ } else { expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); if (expired) { dput(dentry); break; } } next: dput(dentry); spin_lock(&dcache_lock); next = next->next; } if ( expired ) { DPRINTK("returning %p %.*s", expired, (int)expired->d_name.len, expired->d_name.name); spin_lock(&dcache_lock); list_del(&expired->d_parent->d_subdirs); list_add(&expired->d_parent->d_subdirs, &expired->d_u.d_child); spin_unlock(&dcache_lock); return expired; } spin_unlock(&dcache_lock); return NULL; }
/* Check a directory tree of mount points for busyness * The tree is not busy iff no mountpoints are busy */ static int autofs4_tree_busy(struct vfsmount *mnt, struct dentry *top, unsigned long timeout, int do_now) { struct autofs_info *top_ino = autofs4_dentry_ino(top); struct dentry *p; DPRINTK("top %p %.*s", top, (int)top->d_name.len, top->d_name.name); /* Negative dentry - give up */ if (!simple_positive(top)) return 1; spin_lock(&dcache_lock); for (p = top; p; p = next_dentry(p, top)) { /* Negative dentry - give up */ if (!simple_positive(p)) continue; DPRINTK("dentry %p %.*s", p, (int) p->d_name.len, p->d_name.name); p = dget(p); spin_unlock(&dcache_lock); /* * Is someone visiting anywhere in the subtree ? * If there's no mount we need to check the usage * count for the autofs dentry. * If the fs is busy update the expiry counter. */ if (d_mountpoint(p)) { if (autofs4_mount_busy(mnt, p)) { top_ino->last_used = jiffies; dput(p); return 1; } } else { struct autofs_info *ino = autofs4_dentry_ino(p); unsigned int ino_count = atomic_read(&ino->count); /* allow for dget above and top is already dgot */ if (p == top) ino_count += 2; else ino_count++; if (atomic_read(&p->d_count) > ino_count) { top_ino->last_used = jiffies; dput(p); return 1; } } dput(p); spin_lock(&dcache_lock); } spin_unlock(&dcache_lock); /* Timeout of a tree mount is ultimately determined by its top dentry */ if (!autofs4_can_expire(top, timeout, do_now)) return 1; return 0; }
/* * Find an eligible tree to time-out * A tree is eligible if :- * - it is unused by any user process * - it has been unused for exp_timeout time */ struct dentry *autofs4_expire_indirect(struct super_block *sb, struct vfsmount *mnt, struct autofs_sb_info *sbi, int how) { unsigned long timeout; struct dentry *root = sb->s_root; struct dentry *expired = NULL; struct list_head *next; int do_now = how & AUTOFS_EXP_IMMEDIATE; int exp_leaves = how & AUTOFS_EXP_LEAVES; struct autofs_info *ino; unsigned int ino_count; if (!root) return NULL; now = jiffies; timeout = sbi->exp_timeout; spin_lock(&dcache_lock); next = root->d_subdirs.next; /* On exit from the loop expire is set to a dgot dentry * to expire or it's NULL */ while ( next != &root->d_subdirs ) { struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); /* Negative dentry - give up */ if (!simple_positive(dentry)) { next = next->next; continue; } dentry = dget(dentry); spin_unlock(&dcache_lock); spin_lock(&sbi->fs_lock); ino = autofs4_dentry_ino(dentry); /* * Case 1: (i) indirect mount or top level pseudo direct mount * (autofs-4.1). * (ii) indirect mount with offset mount, check the "/" * offset (autofs-5.0+). */ if (d_mountpoint(dentry)) { DPRINTK("checking mountpoint %p %.*s", dentry, (int)dentry->d_name.len, dentry->d_name.name); /* Path walk currently on this dentry? */ ino_count = atomic_read(&ino->count) + 2; if (atomic_read(&dentry->d_count) > ino_count) goto next; /* Can we umount this guy */ if (autofs4_mount_busy(mnt, dentry)) goto next; /* Can we expire this guy */ if (autofs4_can_expire(dentry, timeout, do_now)) { expired = dentry; goto found; } goto next; } if (simple_empty(dentry)) goto next; /* Case 2: tree mount, expire iff entire tree is not busy */ if (!exp_leaves) { /* Path walk currently on this dentry? */ ino_count = atomic_read(&ino->count) + 1; if (atomic_read(&dentry->d_count) > ino_count) goto next; if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { expired = dentry; goto found; } /* * Case 3: pseudo direct mount, expire individual leaves * (autofs-4.1). */ } else { /* Path walk currently on this dentry? */ ino_count = atomic_read(&ino->count) + 1; if (atomic_read(&dentry->d_count) > ino_count) goto next; expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); if (expired) { dput(dentry); goto found; } } next: spin_unlock(&sbi->fs_lock); dput(dentry); spin_lock(&dcache_lock); next = next->next; } spin_unlock(&dcache_lock); return NULL; found: DPRINTK("returning %p %.*s", expired, (int)expired->d_name.len, expired->d_name.name); ino = autofs4_dentry_ino(expired); ino->flags |= AUTOFS_INF_EXPIRING; init_completion(&ino->expire_complete); spin_unlock(&sbi->fs_lock); spin_lock(&dcache_lock); list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); spin_unlock(&dcache_lock); return expired; }
/* Check a directory tree of mount points for busyness * The tree is not busy iff no mountpoints are busy */ static int autofs4_tree_busy(struct vfsmount *mnt, struct dentry *top, unsigned long timeout, int do_now) { struct autofs_info *top_ino = autofs4_dentry_ino(top); struct dentry *p; DPRINTK("top %p %.*s", top, (int)top->d_name.len, top->d_name.name); /* Negative dentry - give up */ if (!simple_positive(top)) return 1; p = NULL; while ((p = get_next_positive_dentry(p, top))) { DPRINTK("dentry %p %.*s", p, (int) p->d_name.len, p->d_name.name); /* * Is someone visiting anywhere in the subtree ? * If there's no mount we need to check the usage * count for the autofs dentry. * If the fs is busy update the expiry counter. */ if (d_mountpoint(p)) { if (autofs4_mount_busy(mnt, p)) { top_ino->last_used = jiffies; dput(p); return 1; } } else { struct autofs_info *ino = autofs4_dentry_ino(p); unsigned int ino_count = atomic_read(&ino->count); /* * Clean stale dentries below that have not been * invalidated after a mount fail during lookup */ d_invalidate(p); /* allow for dget above and top is already dgot */ if (p == top) ino_count += 2; else ino_count++; if (p->d_count > ino_count) { top_ino->last_used = jiffies; dput(p); return 1; } } } /* Timeout of a tree mount is ultimately determined by its top dentry */ if (!autofs4_can_expire(top, timeout, do_now)) return 1; return 0; }