/* * Make the autofs mount point catatonic, no longer responsive to * mount requests. Also closes the kernel pipe file descriptor. */ static int autofs_dev_ioctl_catatonic(struct file *fp, struct autofs_sb_info *sbi, struct autofs_dev_ioctl *param) { autofs4_catatonic_mode(sbi); return 0; }
void autofs4_kill_sb(struct super_block *sb) { struct autofs_sb_info *sbi = autofs4_sbi(sb); /* * In the event of a failure in get_sb_nodev the superblock * info is not present so nothing else has been setup, so * just call kill_anon_super when we are called from * deactivate_super. */ if (!sbi) goto out_kill_sb; /* Free wait queues, close pipe */ autofs4_catatonic_mode(sbi); /* Clean up and release dangling references */ autofs4_force_release(sbi); sb->s_fs_info = NULL; kfree(sbi); out_kill_sb: DPRINTK("shutting down"); kill_anon_super(sb); }
static void autofs4_put_super(struct super_block *sb) { struct autofs_sb_info *sbi = autofs4_sbi(sb); sb->u.generic_sbp = NULL; if ( !sbi->catatonic ) autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */ kfree(sbi); DPRINTK(("autofs: shutting down\n")); }
/* * ioctl()'s on the root directory is the chief method for the daemon to * generate kernel reactions */ static int autofs4_root_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb); void __user *p = (void __user *)arg; DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u", cmd,arg,sbi,process_group(current)); if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT ) return -ENOTTY; if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) return -EPERM; switch(cmd) { case AUTOFS_IOC_READY: /* Wait queue: go ahead and retry */ return autofs4_wait_release(sbi,(autofs_wqt_t)arg,0); case AUTOFS_IOC_FAIL: /* Wait queue: fail with ENOENT */ return autofs4_wait_release(sbi,(autofs_wqt_t)arg,-ENOENT); case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */ autofs4_catatonic_mode(sbi); return 0; case AUTOFS_IOC_PROTOVER: /* Get protocol version */ return autofs4_get_protover(sbi, p); case AUTOFS_IOC_PROTOSUBVER: /* Get protocol sub version */ return autofs4_get_protosubver(sbi, p); case AUTOFS_IOC_SETTIMEOUT: return autofs4_get_set_timeout(sbi, p); case AUTOFS_IOC_TOGGLEREGHOST: return autofs4_toggle_reghost(sbi, p); case AUTOFS_IOC_ASKREGHOST: return autofs4_ask_reghost(sbi, p); case AUTOFS_IOC_ASKUMOUNT: return autofs4_ask_umount(filp->f_vfsmnt, p); /* return a single thing to expire */ case AUTOFS_IOC_EXPIRE: return autofs4_expire_run(inode->i_sb,filp->f_vfsmnt,sbi, p); /* same as above, but can send multiple expires through pipe */ case AUTOFS_IOC_EXPIRE_MULTI: return autofs4_expire_multi(inode->i_sb,filp->f_vfsmnt,sbi, p); default: return -ENOSYS; } }
static void autofs4_notify_daemon(struct autofs_sb_info *sbi, struct autofs_wait_queue *wq, int type) { union autofs_packet_union pkt; size_t pktsz; DPRINTK(("autofs4_notify: wait id = 0x%08lx, name = %.*s, type=%d\n", (unsigned long) wq->wait_queue_token, wq->len, wq->name, type)); memset(&pkt,0,sizeof pkt); /* For security reasons */ pkt.hdr.proto_version = sbi->version; pkt.hdr.type = type; if (type == autofs_ptype_missing) { struct autofs_packet_missing *mp = &pkt.missing; pktsz = sizeof(*mp); mp->wait_queue_token = wq->wait_queue_token; mp->len = wq->len; memcpy(mp->name, wq->name, wq->len); mp->name[wq->len] = '\0'; } else if (type == autofs_ptype_expire_multi) { struct autofs_packet_expire_multi *ep = &pkt.expire_multi; pktsz = sizeof(*ep); ep->wait_queue_token = wq->wait_queue_token; ep->len = wq->len; memcpy(ep->name, wq->name, wq->len); ep->name[wq->len] = '\0'; } else { printk("autofs4_notify_daemon: bad type %d!\n", type); return; } if (autofs4_write(sbi->pipe, &pkt, pktsz)) autofs4_catatonic_mode(sbi); }
static void autofs4_notify_daemon(struct autofs_sb_info *sbi, struct autofs_wait_queue *wq, int type) { union { struct autofs_packet_hdr hdr; union autofs_packet_union v4_pkt; union autofs_v5_packet_union v5_pkt; } pkt; struct file *pipe = NULL; size_t pktsz; DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d", wq->wait_queue_token, wq->name.len, wq->name.name, type); memset(&pkt,0,sizeof pkt); /* For security reasons */ pkt.hdr.proto_version = sbi->version; pkt.hdr.type = type; switch (type) { /* Kernel protocol v4 missing and expire packets */ case autofs_ptype_missing: { struct autofs_packet_missing *mp = &pkt.v4_pkt.missing; pktsz = sizeof(*mp); mp->wait_queue_token = wq->wait_queue_token; mp->len = wq->name.len; memcpy(mp->name, wq->name.name, wq->name.len); mp->name[wq->name.len] = '\0'; break; } case autofs_ptype_expire_multi: { struct autofs_packet_expire_multi *ep = &pkt.v4_pkt.expire_multi; pktsz = sizeof(*ep); ep->wait_queue_token = wq->wait_queue_token; ep->len = wq->name.len; memcpy(ep->name, wq->name.name, wq->name.len); ep->name[wq->name.len] = '\0'; break; } /* * Kernel protocol v5 packet for handling indirect and direct * mount missing and expire requests */ case autofs_ptype_missing_indirect: case autofs_ptype_expire_indirect: case autofs_ptype_missing_direct: case autofs_ptype_expire_direct: { struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; pktsz = sizeof(*packet); packet->wait_queue_token = wq->wait_queue_token; packet->len = wq->name.len; memcpy(packet->name, wq->name.name, wq->name.len); packet->name[wq->name.len] = '\0'; packet->dev = wq->dev; packet->ino = wq->ino; packet->uid = wq->uid; packet->gid = wq->gid; packet->pid = wq->pid; packet->tgid = wq->tgid; break; } default: printk(KERN_INFO "autofs4_notify_daemon: bad type %d!\n", type); return; } /* Check if we have become catatonic */ mutex_lock(&sbi->wq_mutex); if (!sbi->catatonic) { pipe = sbi->pipe; get_file(pipe); } mutex_unlock(&sbi->wq_mutex); if (pipe) { if (autofs4_write(pipe, &pkt, pktsz)) autofs4_catatonic_mode(sbi); fput(pipe); } }