xref: /linux/fs/lockd/svcshare.c (revision 4e6814b1750770213ab5b81bc04d8b941435a7b2)
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 
18 #include "lockd.h"
19 #include "share.h"
20 
21 static inline int
22 nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh)
23 {
24 	return share->s_owner.len == oh->len
25 	    && !memcmp(share->s_owner.data, oh->data, oh->len);
26 }
27 
28 /**
29  * nlmsvc_share_file - create a share
30  * @host: Network client peer
31  * @file: File to be shared
32  * @oh: Share owner handle
33  * @access: Requested access mode
34  * @mode: Requested file sharing mode
35  *
36  * Returns an NLM status code.
37  */
38 __be32
39 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
40 		  struct xdr_netobj *oh, u32 access, u32 mode)
41 {
42 	struct nlm_share	*share;
43 	u8			*ohdata;
44 
45 	if (nlmsvc_file_cannot_lock(file))
46 		return nlm_lck_denied_nolocks;
47 
48 	for (share = file->f_shares; share; share = share->s_next) {
49 		if (share->s_host == host && nlm_cmp_owner(share, oh))
50 			goto update;
51 		if ((access & share->s_mode) || (mode & share->s_access))
52 			return nlm_lck_denied;
53 	}
54 
55 	share = kmalloc(sizeof(*share) + oh->len, GFP_KERNEL);
56 	if (share == NULL)
57 		return nlm_lck_denied_nolocks;
58 
59 	/* Copy owner handle */
60 	ohdata = (u8 *) (share + 1);
61 	memcpy(ohdata, oh->data, oh->len);
62 
63 	share->s_file	    = file;
64 	share->s_host       = host;
65 	share->s_owner.data = ohdata;
66 	share->s_owner.len  = oh->len;
67 	share->s_next       = file->f_shares;
68 	file->f_shares      = share;
69 
70 update:
71 	share->s_access = access;
72 	share->s_mode = mode;
73 	return nlm_granted;
74 }
75 
76 /**
77  * nlmsvc_unshare_file - delete a share
78  * @host: Network client peer
79  * @file: File to be unshared
80  * @oh: Share owner handle
81  *
82  * Returns an NLM status code.
83  */
84 __be32
85 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
86 		    struct xdr_netobj *oh)
87 {
88 	struct nlm_share	*share, **shpp;
89 
90 	if (nlmsvc_file_cannot_lock(file))
91 		return nlm_lck_denied_nolocks;
92 
93 	for (shpp = &file->f_shares; (share = *shpp) != NULL;
94 					shpp = &share->s_next) {
95 		if (share->s_host == host && nlm_cmp_owner(share, oh)) {
96 			*shpp = share->s_next;
97 			kfree(share);
98 			return nlm_granted;
99 		}
100 	}
101 
102 	/* X/Open spec says return success even if there was no
103 	 * corresponding share. */
104 	return nlm_granted;
105 }
106 
107 /*
108  * Traverse all shares for a given file, and delete
109  * those owned by the given (type of) host
110  */
111 void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file,
112 		nlm_host_match_fn_t match)
113 {
114 	struct nlm_share	*share, **shpp;
115 
116 	shpp = &file->f_shares;
117 	while ((share = *shpp) !=  NULL) {
118 		if (match(share->s_host, host)) {
119 			*shpp = share->s_next;
120 			kfree(share);
121 			continue;
122 		}
123 		shpp = &share->s_next;
124 	}
125 }
126