18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved 48c2ecf20Sopenharmony_ci * Copyright 2001-2006 Ian Kent <raven@themaw.net> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 88c2ecf20Sopenharmony_ci#include "autofs_i.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* We make this a static variable rather than a part of the superblock; it 118c2ecf20Sopenharmony_ci * is better if we don't reassign numbers easily even across filesystems 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_cistatic autofs_wqt_t autofs_next_wait_queue = 1; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_civoid autofs_catatonic_mode(struct autofs_sb_info *sbi) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci struct autofs_wait_queue *wq, *nwq; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci mutex_lock(&sbi->wq_mutex); 208c2ecf20Sopenharmony_ci if (sbi->flags & AUTOFS_SBI_CATATONIC) { 218c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 228c2ecf20Sopenharmony_ci return; 238c2ecf20Sopenharmony_ci } 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci pr_debug("entering catatonic mode\n"); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci sbi->flags |= AUTOFS_SBI_CATATONIC; 288c2ecf20Sopenharmony_ci wq = sbi->queues; 298c2ecf20Sopenharmony_ci sbi->queues = NULL; /* Erase all wait queues */ 308c2ecf20Sopenharmony_ci while (wq) { 318c2ecf20Sopenharmony_ci nwq = wq->next; 328c2ecf20Sopenharmony_ci wq->status = -ENOENT; /* Magic is gone - report failure */ 338c2ecf20Sopenharmony_ci kfree(wq->name.name); 348c2ecf20Sopenharmony_ci wq->name.name = NULL; 358c2ecf20Sopenharmony_ci wake_up_interruptible(&wq->queue); 368c2ecf20Sopenharmony_ci if (!--wq->wait_ctr) 378c2ecf20Sopenharmony_ci kfree(wq); 388c2ecf20Sopenharmony_ci wq = nwq; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci fput(sbi->pipe); /* Close the pipe */ 418c2ecf20Sopenharmony_ci sbi->pipe = NULL; 428c2ecf20Sopenharmony_ci sbi->pipefd = -1; 438c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int autofs_write(struct autofs_sb_info *sbi, 478c2ecf20Sopenharmony_ci struct file *file, const void *addr, int bytes) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci unsigned long sigpipe, flags; 508c2ecf20Sopenharmony_ci const char *data = (const char *)addr; 518c2ecf20Sopenharmony_ci ssize_t wr = 0; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci sigpipe = sigismember(¤t->pending.signal, SIGPIPE); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci mutex_lock(&sbi->pipe_mutex); 568c2ecf20Sopenharmony_ci while (bytes) { 578c2ecf20Sopenharmony_ci wr = __kernel_write(file, data, bytes, NULL); 588c2ecf20Sopenharmony_ci if (wr <= 0) 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci data += wr; 618c2ecf20Sopenharmony_ci bytes -= wr; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci mutex_unlock(&sbi->pipe_mutex); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Keep the currently executing process from receiving a 668c2ecf20Sopenharmony_ci * SIGPIPE unless it was already supposed to get one 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci if (wr == -EPIPE && !sigpipe) { 698c2ecf20Sopenharmony_ci spin_lock_irqsave(¤t->sighand->siglock, flags); 708c2ecf20Sopenharmony_ci sigdelset(¤t->pending.signal, SIGPIPE); 718c2ecf20Sopenharmony_ci recalc_sigpending(); 728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(¤t->sighand->siglock, flags); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* if 'wr' returned 0 (impossible) we assume -EIO (safe) */ 768c2ecf20Sopenharmony_ci return bytes == 0 ? 0 : wr < 0 ? wr : -EIO; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void autofs_notify_daemon(struct autofs_sb_info *sbi, 808c2ecf20Sopenharmony_ci struct autofs_wait_queue *wq, 818c2ecf20Sopenharmony_ci int type) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci union { 848c2ecf20Sopenharmony_ci struct autofs_packet_hdr hdr; 858c2ecf20Sopenharmony_ci union autofs_packet_union v4_pkt; 868c2ecf20Sopenharmony_ci union autofs_v5_packet_union v5_pkt; 878c2ecf20Sopenharmony_ci } pkt; 888c2ecf20Sopenharmony_ci struct file *pipe = NULL; 898c2ecf20Sopenharmony_ci size_t pktsz; 908c2ecf20Sopenharmony_ci int ret; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci pr_debug("wait id = 0x%08lx, name = %.*s, type=%d\n", 938c2ecf20Sopenharmony_ci (unsigned long) wq->wait_queue_token, 948c2ecf20Sopenharmony_ci wq->name.len, wq->name.name, type); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci memset(&pkt, 0, sizeof(pkt)); /* For security reasons */ 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci pkt.hdr.proto_version = sbi->version; 998c2ecf20Sopenharmony_ci pkt.hdr.type = type; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci switch (type) { 1028c2ecf20Sopenharmony_ci /* Kernel protocol v4 missing and expire packets */ 1038c2ecf20Sopenharmony_ci case autofs_ptype_missing: 1048c2ecf20Sopenharmony_ci { 1058c2ecf20Sopenharmony_ci struct autofs_packet_missing *mp = &pkt.v4_pkt.missing; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci pktsz = sizeof(*mp); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci mp->wait_queue_token = wq->wait_queue_token; 1108c2ecf20Sopenharmony_ci mp->len = wq->name.len; 1118c2ecf20Sopenharmony_ci memcpy(mp->name, wq->name.name, wq->name.len); 1128c2ecf20Sopenharmony_ci mp->name[wq->name.len] = '\0'; 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci case autofs_ptype_expire_multi: 1168c2ecf20Sopenharmony_ci { 1178c2ecf20Sopenharmony_ci struct autofs_packet_expire_multi *ep = 1188c2ecf20Sopenharmony_ci &pkt.v4_pkt.expire_multi; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci pktsz = sizeof(*ep); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci ep->wait_queue_token = wq->wait_queue_token; 1238c2ecf20Sopenharmony_ci ep->len = wq->name.len; 1248c2ecf20Sopenharmony_ci memcpy(ep->name, wq->name.name, wq->name.len); 1258c2ecf20Sopenharmony_ci ep->name[wq->name.len] = '\0'; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci /* 1298c2ecf20Sopenharmony_ci * Kernel protocol v5 packet for handling indirect and direct 1308c2ecf20Sopenharmony_ci * mount missing and expire requests 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci case autofs_ptype_missing_indirect: 1338c2ecf20Sopenharmony_ci case autofs_ptype_expire_indirect: 1348c2ecf20Sopenharmony_ci case autofs_ptype_missing_direct: 1358c2ecf20Sopenharmony_ci case autofs_ptype_expire_direct: 1368c2ecf20Sopenharmony_ci { 1378c2ecf20Sopenharmony_ci struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; 1388c2ecf20Sopenharmony_ci struct user_namespace *user_ns = sbi->pipe->f_cred->user_ns; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci pktsz = sizeof(*packet); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci packet->wait_queue_token = wq->wait_queue_token; 1438c2ecf20Sopenharmony_ci packet->len = wq->name.len; 1448c2ecf20Sopenharmony_ci memcpy(packet->name, wq->name.name, wq->name.len); 1458c2ecf20Sopenharmony_ci packet->name[wq->name.len] = '\0'; 1468c2ecf20Sopenharmony_ci packet->dev = wq->dev; 1478c2ecf20Sopenharmony_ci packet->ino = wq->ino; 1488c2ecf20Sopenharmony_ci packet->uid = from_kuid_munged(user_ns, wq->uid); 1498c2ecf20Sopenharmony_ci packet->gid = from_kgid_munged(user_ns, wq->gid); 1508c2ecf20Sopenharmony_ci packet->pid = wq->pid; 1518c2ecf20Sopenharmony_ci packet->tgid = wq->tgid; 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci default: 1558c2ecf20Sopenharmony_ci pr_warn("bad type %d!\n", type); 1568c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci pipe = get_file(sbi->pipe); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci switch (ret = autofs_write(sbi, pipe, &pkt, pktsz)) { 1658c2ecf20Sopenharmony_ci case 0: 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci case -ENOMEM: 1688c2ecf20Sopenharmony_ci case -ERESTARTSYS: 1698c2ecf20Sopenharmony_ci /* Just fail this one */ 1708c2ecf20Sopenharmony_ci autofs_wait_release(sbi, wq->wait_queue_token, ret); 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci default: 1738c2ecf20Sopenharmony_ci autofs_catatonic_mode(sbi); 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci fput(pipe); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int autofs_getpath(struct autofs_sb_info *sbi, 1808c2ecf20Sopenharmony_ci struct dentry *dentry, char *name) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct dentry *root = sbi->sb->s_root; 1838c2ecf20Sopenharmony_ci struct dentry *tmp; 1848c2ecf20Sopenharmony_ci char *buf; 1858c2ecf20Sopenharmony_ci char *p; 1868c2ecf20Sopenharmony_ci int len; 1878c2ecf20Sopenharmony_ci unsigned seq; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cirename_retry: 1908c2ecf20Sopenharmony_ci buf = name; 1918c2ecf20Sopenharmony_ci len = 0; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci seq = read_seqbegin(&rename_lock); 1948c2ecf20Sopenharmony_ci rcu_read_lock(); 1958c2ecf20Sopenharmony_ci spin_lock(&sbi->fs_lock); 1968c2ecf20Sopenharmony_ci for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) 1978c2ecf20Sopenharmony_ci len += tmp->d_name.len + 1; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!len || --len > NAME_MAX) { 2008c2ecf20Sopenharmony_ci spin_unlock(&sbi->fs_lock); 2018c2ecf20Sopenharmony_ci rcu_read_unlock(); 2028c2ecf20Sopenharmony_ci if (read_seqretry(&rename_lock, seq)) 2038c2ecf20Sopenharmony_ci goto rename_retry; 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci *(buf + len) = '\0'; 2088c2ecf20Sopenharmony_ci p = buf + len - dentry->d_name.len; 2098c2ecf20Sopenharmony_ci strncpy(p, dentry->d_name.name, dentry->d_name.len); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci for (tmp = dentry->d_parent; tmp != root ; tmp = tmp->d_parent) { 2128c2ecf20Sopenharmony_ci *(--p) = '/'; 2138c2ecf20Sopenharmony_ci p -= tmp->d_name.len; 2148c2ecf20Sopenharmony_ci strncpy(p, tmp->d_name.name, tmp->d_name.len); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci spin_unlock(&sbi->fs_lock); 2178c2ecf20Sopenharmony_ci rcu_read_unlock(); 2188c2ecf20Sopenharmony_ci if (read_seqretry(&rename_lock, seq)) 2198c2ecf20Sopenharmony_ci goto rename_retry; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return len; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic struct autofs_wait_queue * 2258c2ecf20Sopenharmony_ciautofs_find_wait(struct autofs_sb_info *sbi, const struct qstr *qstr) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct autofs_wait_queue *wq; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci for (wq = sbi->queues; wq; wq = wq->next) { 2308c2ecf20Sopenharmony_ci if (wq->name.hash == qstr->hash && 2318c2ecf20Sopenharmony_ci wq->name.len == qstr->len && 2328c2ecf20Sopenharmony_ci wq->name.name && 2338c2ecf20Sopenharmony_ci !memcmp(wq->name.name, qstr->name, qstr->len)) 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci return wq; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* 2408c2ecf20Sopenharmony_ci * Check if we have a valid request. 2418c2ecf20Sopenharmony_ci * Returns 2428c2ecf20Sopenharmony_ci * 1 if the request should continue. 2438c2ecf20Sopenharmony_ci * In this case we can return an autofs_wait_queue entry if one is 2448c2ecf20Sopenharmony_ci * found or NULL to idicate a new wait needs to be created. 2458c2ecf20Sopenharmony_ci * 0 or a negative errno if the request shouldn't continue. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_cistatic int validate_request(struct autofs_wait_queue **wait, 2488c2ecf20Sopenharmony_ci struct autofs_sb_info *sbi, 2498c2ecf20Sopenharmony_ci const struct qstr *qstr, 2508c2ecf20Sopenharmony_ci const struct path *path, enum autofs_notify notify) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct dentry *dentry = path->dentry; 2538c2ecf20Sopenharmony_ci struct autofs_wait_queue *wq; 2548c2ecf20Sopenharmony_ci struct autofs_info *ino; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (sbi->flags & AUTOFS_SBI_CATATONIC) 2578c2ecf20Sopenharmony_ci return -ENOENT; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Wait in progress, continue; */ 2608c2ecf20Sopenharmony_ci wq = autofs_find_wait(sbi, qstr); 2618c2ecf20Sopenharmony_ci if (wq) { 2628c2ecf20Sopenharmony_ci *wait = wq; 2638c2ecf20Sopenharmony_ci return 1; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci *wait = NULL; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* If we don't yet have any info this is a new request */ 2698c2ecf20Sopenharmony_ci ino = autofs_dentry_ino(dentry); 2708c2ecf20Sopenharmony_ci if (!ino) 2718c2ecf20Sopenharmony_ci return 1; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* 2748c2ecf20Sopenharmony_ci * If we've been asked to wait on an existing expire (NFY_NONE) 2758c2ecf20Sopenharmony_ci * but there is no wait in the queue ... 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci if (notify == NFY_NONE) { 2788c2ecf20Sopenharmony_ci /* 2798c2ecf20Sopenharmony_ci * Either we've betean the pending expire to post it's 2808c2ecf20Sopenharmony_ci * wait or it finished while we waited on the mutex. 2818c2ecf20Sopenharmony_ci * So we need to wait till either, the wait appears 2828c2ecf20Sopenharmony_ci * or the expire finishes. 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci while (ino->flags & AUTOFS_INF_EXPIRING) { 2868c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 2878c2ecf20Sopenharmony_ci schedule_timeout_interruptible(HZ/10); 2888c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&sbi->wq_mutex)) 2898c2ecf20Sopenharmony_ci return -EINTR; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (sbi->flags & AUTOFS_SBI_CATATONIC) 2928c2ecf20Sopenharmony_ci return -ENOENT; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci wq = autofs_find_wait(sbi, qstr); 2958c2ecf20Sopenharmony_ci if (wq) { 2968c2ecf20Sopenharmony_ci *wait = wq; 2978c2ecf20Sopenharmony_ci return 1; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* 3028c2ecf20Sopenharmony_ci * Not ideal but the status has already gone. Of the two 3038c2ecf20Sopenharmony_ci * cases where we wait on NFY_NONE neither depend on the 3048c2ecf20Sopenharmony_ci * return status of the wait. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* 3108c2ecf20Sopenharmony_ci * If we've been asked to trigger a mount and the request 3118c2ecf20Sopenharmony_ci * completed while we waited on the mutex ... 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_ci if (notify == NFY_MOUNT) { 3148c2ecf20Sopenharmony_ci struct dentry *new = NULL; 3158c2ecf20Sopenharmony_ci struct path this; 3168c2ecf20Sopenharmony_ci int valid = 1; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* 3198c2ecf20Sopenharmony_ci * If the dentry was successfully mounted while we slept 3208c2ecf20Sopenharmony_ci * on the wait queue mutex we can return success. If it 3218c2ecf20Sopenharmony_ci * isn't mounted (doesn't have submounts for the case of 3228c2ecf20Sopenharmony_ci * a multi-mount with no mount at it's base) we can 3238c2ecf20Sopenharmony_ci * continue on and create a new request. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci if (!IS_ROOT(dentry)) { 3268c2ecf20Sopenharmony_ci if (d_unhashed(dentry) && 3278c2ecf20Sopenharmony_ci d_really_is_positive(dentry)) { 3288c2ecf20Sopenharmony_ci struct dentry *parent = dentry->d_parent; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci new = d_lookup(parent, &dentry->d_name); 3318c2ecf20Sopenharmony_ci if (new) 3328c2ecf20Sopenharmony_ci dentry = new; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci this.mnt = path->mnt; 3368c2ecf20Sopenharmony_ci this.dentry = dentry; 3378c2ecf20Sopenharmony_ci if (path_has_submounts(&this)) 3388c2ecf20Sopenharmony_ci valid = 0; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (new) 3418c2ecf20Sopenharmony_ci dput(new); 3428c2ecf20Sopenharmony_ci return valid; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return 1; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ciint autofs_wait(struct autofs_sb_info *sbi, 3498c2ecf20Sopenharmony_ci const struct path *path, enum autofs_notify notify) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct dentry *dentry = path->dentry; 3528c2ecf20Sopenharmony_ci struct autofs_wait_queue *wq; 3538c2ecf20Sopenharmony_ci struct qstr qstr; 3548c2ecf20Sopenharmony_ci char *name; 3558c2ecf20Sopenharmony_ci int status, ret, type; 3568c2ecf20Sopenharmony_ci pid_t pid; 3578c2ecf20Sopenharmony_ci pid_t tgid; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* In catatonic mode, we don't wait for nobody */ 3608c2ecf20Sopenharmony_ci if (sbi->flags & AUTOFS_SBI_CATATONIC) 3618c2ecf20Sopenharmony_ci return -ENOENT; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * Try translating pids to the namespace of the daemon. 3658c2ecf20Sopenharmony_ci * 3668c2ecf20Sopenharmony_ci * Zero means failure: we are in an unrelated pid namespace. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci pid = task_pid_nr_ns(current, ns_of_pid(sbi->oz_pgrp)); 3698c2ecf20Sopenharmony_ci tgid = task_tgid_nr_ns(current, ns_of_pid(sbi->oz_pgrp)); 3708c2ecf20Sopenharmony_ci if (pid == 0 || tgid == 0) 3718c2ecf20Sopenharmony_ci return -ENOENT; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (d_really_is_negative(dentry)) { 3748c2ecf20Sopenharmony_ci /* 3758c2ecf20Sopenharmony_ci * A wait for a negative dentry is invalid for certain 3768c2ecf20Sopenharmony_ci * cases. A direct or offset mount "always" has its mount 3778c2ecf20Sopenharmony_ci * point directory created and so the request dentry must 3788c2ecf20Sopenharmony_ci * be positive or the map key doesn't exist. The situation 3798c2ecf20Sopenharmony_ci * is very similar for indirect mounts except only dentrys 3808c2ecf20Sopenharmony_ci * in the root of the autofs file system may be negative. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci if (autofs_type_trigger(sbi->type)) 3838c2ecf20Sopenharmony_ci return -ENOENT; 3848c2ecf20Sopenharmony_ci else if (!IS_ROOT(dentry->d_parent)) 3858c2ecf20Sopenharmony_ci return -ENOENT; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci name = kmalloc(NAME_MAX + 1, GFP_KERNEL); 3898c2ecf20Sopenharmony_ci if (!name) 3908c2ecf20Sopenharmony_ci return -ENOMEM; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* If this is a direct mount request create a dummy name */ 3938c2ecf20Sopenharmony_ci if (IS_ROOT(dentry) && autofs_type_trigger(sbi->type)) 3948c2ecf20Sopenharmony_ci qstr.len = sprintf(name, "%p", dentry); 3958c2ecf20Sopenharmony_ci else { 3968c2ecf20Sopenharmony_ci qstr.len = autofs_getpath(sbi, dentry, name); 3978c2ecf20Sopenharmony_ci if (!qstr.len) { 3988c2ecf20Sopenharmony_ci kfree(name); 3998c2ecf20Sopenharmony_ci return -ENOENT; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci qstr.name = name; 4038c2ecf20Sopenharmony_ci qstr.hash = full_name_hash(dentry, name, qstr.len); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&sbi->wq_mutex)) { 4068c2ecf20Sopenharmony_ci kfree(qstr.name); 4078c2ecf20Sopenharmony_ci return -EINTR; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci ret = validate_request(&wq, sbi, &qstr, path, notify); 4118c2ecf20Sopenharmony_ci if (ret <= 0) { 4128c2ecf20Sopenharmony_ci if (ret != -EINTR) 4138c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 4148c2ecf20Sopenharmony_ci kfree(qstr.name); 4158c2ecf20Sopenharmony_ci return ret; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (!wq) { 4198c2ecf20Sopenharmony_ci /* Create a new wait queue */ 4208c2ecf20Sopenharmony_ci wq = kmalloc(sizeof(struct autofs_wait_queue), GFP_KERNEL); 4218c2ecf20Sopenharmony_ci if (!wq) { 4228c2ecf20Sopenharmony_ci kfree(qstr.name); 4238c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 4248c2ecf20Sopenharmony_ci return -ENOMEM; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci wq->wait_queue_token = autofs_next_wait_queue; 4288c2ecf20Sopenharmony_ci if (++autofs_next_wait_queue == 0) 4298c2ecf20Sopenharmony_ci autofs_next_wait_queue = 1; 4308c2ecf20Sopenharmony_ci wq->next = sbi->queues; 4318c2ecf20Sopenharmony_ci sbi->queues = wq; 4328c2ecf20Sopenharmony_ci init_waitqueue_head(&wq->queue); 4338c2ecf20Sopenharmony_ci memcpy(&wq->name, &qstr, sizeof(struct qstr)); 4348c2ecf20Sopenharmony_ci wq->dev = autofs_get_dev(sbi); 4358c2ecf20Sopenharmony_ci wq->ino = autofs_get_ino(sbi); 4368c2ecf20Sopenharmony_ci wq->uid = current_uid(); 4378c2ecf20Sopenharmony_ci wq->gid = current_gid(); 4388c2ecf20Sopenharmony_ci wq->pid = pid; 4398c2ecf20Sopenharmony_ci wq->tgid = tgid; 4408c2ecf20Sopenharmony_ci wq->status = -EINTR; /* Status return if interrupted */ 4418c2ecf20Sopenharmony_ci wq->wait_ctr = 2; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (sbi->version < 5) { 4448c2ecf20Sopenharmony_ci if (notify == NFY_MOUNT) 4458c2ecf20Sopenharmony_ci type = autofs_ptype_missing; 4468c2ecf20Sopenharmony_ci else 4478c2ecf20Sopenharmony_ci type = autofs_ptype_expire_multi; 4488c2ecf20Sopenharmony_ci } else { 4498c2ecf20Sopenharmony_ci if (notify == NFY_MOUNT) 4508c2ecf20Sopenharmony_ci type = autofs_type_trigger(sbi->type) ? 4518c2ecf20Sopenharmony_ci autofs_ptype_missing_direct : 4528c2ecf20Sopenharmony_ci autofs_ptype_missing_indirect; 4538c2ecf20Sopenharmony_ci else 4548c2ecf20Sopenharmony_ci type = autofs_type_trigger(sbi->type) ? 4558c2ecf20Sopenharmony_ci autofs_ptype_expire_direct : 4568c2ecf20Sopenharmony_ci autofs_ptype_expire_indirect; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci pr_debug("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", 4608c2ecf20Sopenharmony_ci (unsigned long) wq->wait_queue_token, wq->name.len, 4618c2ecf20Sopenharmony_ci wq->name.name, notify); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* 4648c2ecf20Sopenharmony_ci * autofs_notify_daemon() may block; it will unlock ->wq_mutex 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci autofs_notify_daemon(sbi, wq, type); 4678c2ecf20Sopenharmony_ci } else { 4688c2ecf20Sopenharmony_ci wq->wait_ctr++; 4698c2ecf20Sopenharmony_ci pr_debug("existing wait id = 0x%08lx, name = %.*s, nfy=%d\n", 4708c2ecf20Sopenharmony_ci (unsigned long) wq->wait_queue_token, wq->name.len, 4718c2ecf20Sopenharmony_ci wq->name.name, notify); 4728c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 4738c2ecf20Sopenharmony_ci kfree(qstr.name); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* 4778c2ecf20Sopenharmony_ci * wq->name.name is NULL iff the lock is already released 4788c2ecf20Sopenharmony_ci * or the mount has been made catatonic. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci wait_event_killable(wq->queue, wq->name.name == NULL); 4818c2ecf20Sopenharmony_ci status = wq->status; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* 4848c2ecf20Sopenharmony_ci * For direct and offset mounts we need to track the requester's 4858c2ecf20Sopenharmony_ci * uid and gid in the dentry info struct. This is so it can be 4868c2ecf20Sopenharmony_ci * supplied, on request, by the misc device ioctl interface. 4878c2ecf20Sopenharmony_ci * This is needed during daemon resatart when reconnecting 4888c2ecf20Sopenharmony_ci * to existing, active, autofs mounts. The uid and gid (and 4898c2ecf20Sopenharmony_ci * related string values) may be used for macro substitution 4908c2ecf20Sopenharmony_ci * in autofs mount maps. 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_ci if (!status) { 4938c2ecf20Sopenharmony_ci struct autofs_info *ino; 4948c2ecf20Sopenharmony_ci struct dentry *de = NULL; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* direct mount or browsable map */ 4978c2ecf20Sopenharmony_ci ino = autofs_dentry_ino(dentry); 4988c2ecf20Sopenharmony_ci if (!ino) { 4998c2ecf20Sopenharmony_ci /* If not lookup actual dentry used */ 5008c2ecf20Sopenharmony_ci de = d_lookup(dentry->d_parent, &dentry->d_name); 5018c2ecf20Sopenharmony_ci if (de) 5028c2ecf20Sopenharmony_ci ino = autofs_dentry_ino(de); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Set mount requester */ 5068c2ecf20Sopenharmony_ci if (ino) { 5078c2ecf20Sopenharmony_ci spin_lock(&sbi->fs_lock); 5088c2ecf20Sopenharmony_ci ino->uid = wq->uid; 5098c2ecf20Sopenharmony_ci ino->gid = wq->gid; 5108c2ecf20Sopenharmony_ci spin_unlock(&sbi->fs_lock); 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (de) 5148c2ecf20Sopenharmony_ci dput(de); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* Are we the last process to need status? */ 5188c2ecf20Sopenharmony_ci mutex_lock(&sbi->wq_mutex); 5198c2ecf20Sopenharmony_ci if (!--wq->wait_ctr) 5208c2ecf20Sopenharmony_ci kfree(wq); 5218c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return status; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciint autofs_wait_release(struct autofs_sb_info *sbi, 5288c2ecf20Sopenharmony_ci autofs_wqt_t wait_queue_token, int status) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct autofs_wait_queue *wq, **wql; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci mutex_lock(&sbi->wq_mutex); 5338c2ecf20Sopenharmony_ci for (wql = &sbi->queues; (wq = *wql) != NULL; wql = &wq->next) { 5348c2ecf20Sopenharmony_ci if (wq->wait_queue_token == wait_queue_token) 5358c2ecf20Sopenharmony_ci break; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (!wq) { 5398c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 5408c2ecf20Sopenharmony_ci return -EINVAL; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci *wql = wq->next; /* Unlink from chain */ 5448c2ecf20Sopenharmony_ci kfree(wq->name.name); 5458c2ecf20Sopenharmony_ci wq->name.name = NULL; /* Do not wait on this queue */ 5468c2ecf20Sopenharmony_ci wq->status = status; 5478c2ecf20Sopenharmony_ci wake_up(&wq->queue); 5488c2ecf20Sopenharmony_ci if (!--wq->wait_ctr) 5498c2ecf20Sopenharmony_ci kfree(wq); 5508c2ecf20Sopenharmony_ci mutex_unlock(&sbi->wq_mutex); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci} 554