162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/lockd/svcshare.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Management of DOS shares. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/time.h> 1162306a36Sopenharmony_ci#include <linux/unistd.h> 1262306a36Sopenharmony_ci#include <linux/string.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h> 1662306a36Sopenharmony_ci#include <linux/sunrpc/svc.h> 1762306a36Sopenharmony_ci#include <linux/lockd/lockd.h> 1862306a36Sopenharmony_ci#include <linux/lockd/share.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic inline int 2162306a36Sopenharmony_cinlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci return share->s_owner.len == oh->len 2462306a36Sopenharmony_ci && !memcmp(share->s_owner.data, oh->data, oh->len); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci__be32 2862306a36Sopenharmony_cinlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, 2962306a36Sopenharmony_ci struct nlm_args *argp) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct nlm_share *share; 3262306a36Sopenharmony_ci struct xdr_netobj *oh = &argp->lock.oh; 3362306a36Sopenharmony_ci u8 *ohdata; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci for (share = file->f_shares; share; share = share->s_next) { 3662306a36Sopenharmony_ci if (share->s_host == host && nlm_cmp_owner(share, oh)) 3762306a36Sopenharmony_ci goto update; 3862306a36Sopenharmony_ci if ((argp->fsm_access & share->s_mode) 3962306a36Sopenharmony_ci || (argp->fsm_mode & share->s_access )) 4062306a36Sopenharmony_ci return nlm_lck_denied; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci share = kmalloc(sizeof(*share) + oh->len, 4462306a36Sopenharmony_ci GFP_KERNEL); 4562306a36Sopenharmony_ci if (share == NULL) 4662306a36Sopenharmony_ci return nlm_lck_denied_nolocks; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Copy owner handle */ 4962306a36Sopenharmony_ci ohdata = (u8 *) (share + 1); 5062306a36Sopenharmony_ci memcpy(ohdata, oh->data, oh->len); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci share->s_file = file; 5362306a36Sopenharmony_ci share->s_host = host; 5462306a36Sopenharmony_ci share->s_owner.data = ohdata; 5562306a36Sopenharmony_ci share->s_owner.len = oh->len; 5662306a36Sopenharmony_ci share->s_next = file->f_shares; 5762306a36Sopenharmony_ci file->f_shares = share; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciupdate: 6062306a36Sopenharmony_ci share->s_access = argp->fsm_access; 6162306a36Sopenharmony_ci share->s_mode = argp->fsm_mode; 6262306a36Sopenharmony_ci return nlm_granted; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* 6662306a36Sopenharmony_ci * Delete a share. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci__be32 6962306a36Sopenharmony_cinlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, 7062306a36Sopenharmony_ci struct nlm_args *argp) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct nlm_share *share, **shpp; 7362306a36Sopenharmony_ci struct xdr_netobj *oh = &argp->lock.oh; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci for (shpp = &file->f_shares; (share = *shpp) != NULL; 7662306a36Sopenharmony_ci shpp = &share->s_next) { 7762306a36Sopenharmony_ci if (share->s_host == host && nlm_cmp_owner(share, oh)) { 7862306a36Sopenharmony_ci *shpp = share->s_next; 7962306a36Sopenharmony_ci kfree(share); 8062306a36Sopenharmony_ci return nlm_granted; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* X/Open spec says return success even if there was no 8562306a36Sopenharmony_ci * corresponding share. */ 8662306a36Sopenharmony_ci return nlm_granted; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * Traverse all shares for a given file, and delete 9162306a36Sopenharmony_ci * those owned by the given (type of) host 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_civoid nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, 9462306a36Sopenharmony_ci nlm_host_match_fn_t match) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct nlm_share *share, **shpp; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci shpp = &file->f_shares; 9962306a36Sopenharmony_ci while ((share = *shpp) != NULL) { 10062306a36Sopenharmony_ci if (match(share->s_host, host)) { 10162306a36Sopenharmony_ci *shpp = share->s_next; 10262306a36Sopenharmony_ci kfree(share); 10362306a36Sopenharmony_ci continue; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci shpp = &share->s_next; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci} 108