1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/fs/lockd/svcshare.c 4 * 5 * Management of DOS shares. 6 * 7 * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de> 8 */ 9 10 #include <linux/time.h> 11 #include <linux/unistd.h> 12 #include <linux/string.h> 13 #include <linux/slab.h> 14 15 #include <linux/sunrpc/clnt.h> 16 #include <linux/sunrpc/svc.h> 17 #include <linux/lockd/lockd.h> 18 #include <linux/lockd/share.h> 19 20 static inline int 21 nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh) 22 { 23 return share->s_owner.len == oh->len 24 && !memcmp(share->s_owner.data, oh->data, oh->len); 25 } 26 27 __be32 28 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, 29 struct nlm_args *argp) 30 { 31 struct nlm_share *share; 32 struct xdr_netobj *oh = &argp->lock.oh; 33 u8 *ohdata; 34 35 if (nlmsvc_file_cannot_lock(file)) 36 return nlm_lck_denied_nolocks; 37 38 for (share = file->f_shares; share; share = share->s_next) { 39 if (share->s_host == host && nlm_cmp_owner(share, oh)) 40 goto update; 41 if ((argp->fsm_access & share->s_mode) 42 || (argp->fsm_mode & share->s_access )) 43 return nlm_lck_denied; 44 } 45 46 share = kmalloc(sizeof(*share) + oh->len, 47 GFP_KERNEL); 48 if (share == NULL) 49 return nlm_lck_denied_nolocks; 50 51 /* Copy owner handle */ 52 ohdata = (u8 *) (share + 1); 53 memcpy(ohdata, oh->data, oh->len); 54 55 share->s_file = file; 56 share->s_host = host; 57 share->s_owner.data = ohdata; 58 share->s_owner.len = oh->len; 59 share->s_next = file->f_shares; 60 file->f_shares = share; 61 62 update: 63 share->s_access = argp->fsm_access; 64 share->s_mode = argp->fsm_mode; 65 return nlm_granted; 66 } 67 68 /* 69 * Delete a share. 70 */ 71 __be32 72 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, 73 struct nlm_args *argp) 74 { 75 struct nlm_share *share, **shpp; 76 struct xdr_netobj *oh = &argp->lock.oh; 77 78 if (nlmsvc_file_cannot_lock(file)) 79 return nlm_lck_denied_nolocks; 80 81 for (shpp = &file->f_shares; (share = *shpp) != NULL; 82 shpp = &share->s_next) { 83 if (share->s_host == host && nlm_cmp_owner(share, oh)) { 84 *shpp = share->s_next; 85 kfree(share); 86 return nlm_granted; 87 } 88 } 89 90 /* X/Open spec says return success even if there was no 91 * corresponding share. */ 92 return nlm_granted; 93 } 94 95 /* 96 * Traverse all shares for a given file, and delete 97 * those owned by the given (type of) host 98 */ 99 void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, 100 nlm_host_match_fn_t match) 101 { 102 struct nlm_share *share, **shpp; 103 104 shpp = &file->f_shares; 105 while ((share = *shpp) != NULL) { 106 if (match(share->s_host, host)) { 107 *shpp = share->s_next; 108 kfree(share); 109 continue; 110 } 111 shpp = &share->s_next; 112 } 113 } 114