1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) 2001 Clemson University and The University of Chicago
4 *
5 * See COPYING in top-level directory.
6 */
7
8#include "protocol.h"
9#include "orangefs-kernel.h"
10
11/* tags assigned to kernel upcall operations */
12static __u64 next_tag_value;
13static DEFINE_SPINLOCK(next_tag_value_lock);
14
15/* the orangefs memory caches */
16
17/* a cache for orangefs upcall/downcall operations */
18static struct kmem_cache *op_cache;
19
20int op_cache_initialize(void)
21{
22	op_cache = kmem_cache_create("orangefs_op_cache",
23				     sizeof(struct orangefs_kernel_op_s),
24				     0,
25				     ORANGEFS_CACHE_CREATE_FLAGS,
26				     NULL);
27
28	if (!op_cache) {
29		gossip_err("Cannot create orangefs_op_cache\n");
30		return -ENOMEM;
31	}
32
33	/* initialize our atomic tag counter */
34	spin_lock(&next_tag_value_lock);
35	next_tag_value = 100;
36	spin_unlock(&next_tag_value_lock);
37	return 0;
38}
39
40int op_cache_finalize(void)
41{
42	kmem_cache_destroy(op_cache);
43	return 0;
44}
45
46char *get_opname_string(struct orangefs_kernel_op_s *new_op)
47{
48	if (new_op) {
49		__s32 type = new_op->upcall.type;
50
51		if (type == ORANGEFS_VFS_OP_FILE_IO)
52			return "OP_FILE_IO";
53		else if (type == ORANGEFS_VFS_OP_LOOKUP)
54			return "OP_LOOKUP";
55		else if (type == ORANGEFS_VFS_OP_CREATE)
56			return "OP_CREATE";
57		else if (type == ORANGEFS_VFS_OP_GETATTR)
58			return "OP_GETATTR";
59		else if (type == ORANGEFS_VFS_OP_REMOVE)
60			return "OP_REMOVE";
61		else if (type == ORANGEFS_VFS_OP_MKDIR)
62			return "OP_MKDIR";
63		else if (type == ORANGEFS_VFS_OP_READDIR)
64			return "OP_READDIR";
65		else if (type == ORANGEFS_VFS_OP_READDIRPLUS)
66			return "OP_READDIRPLUS";
67		else if (type == ORANGEFS_VFS_OP_SETATTR)
68			return "OP_SETATTR";
69		else if (type == ORANGEFS_VFS_OP_SYMLINK)
70			return "OP_SYMLINK";
71		else if (type == ORANGEFS_VFS_OP_RENAME)
72			return "OP_RENAME";
73		else if (type == ORANGEFS_VFS_OP_STATFS)
74			return "OP_STATFS";
75		else if (type == ORANGEFS_VFS_OP_TRUNCATE)
76			return "OP_TRUNCATE";
77		else if (type == ORANGEFS_VFS_OP_RA_FLUSH)
78			return "OP_RA_FLUSH";
79		else if (type == ORANGEFS_VFS_OP_FS_MOUNT)
80			return "OP_FS_MOUNT";
81		else if (type == ORANGEFS_VFS_OP_FS_UMOUNT)
82			return "OP_FS_UMOUNT";
83		else if (type == ORANGEFS_VFS_OP_GETXATTR)
84			return "OP_GETXATTR";
85		else if (type == ORANGEFS_VFS_OP_SETXATTR)
86			return "OP_SETXATTR";
87		else if (type == ORANGEFS_VFS_OP_LISTXATTR)
88			return "OP_LISTXATTR";
89		else if (type == ORANGEFS_VFS_OP_REMOVEXATTR)
90			return "OP_REMOVEXATTR";
91		else if (type == ORANGEFS_VFS_OP_PARAM)
92			return "OP_PARAM";
93		else if (type == ORANGEFS_VFS_OP_PERF_COUNT)
94			return "OP_PERF_COUNT";
95		else if (type == ORANGEFS_VFS_OP_CANCEL)
96			return "OP_CANCEL";
97		else if (type == ORANGEFS_VFS_OP_FSYNC)
98			return "OP_FSYNC";
99		else if (type == ORANGEFS_VFS_OP_FSKEY)
100			return "OP_FSKEY";
101		else if (type == ORANGEFS_VFS_OP_FEATURES)
102			return "OP_FEATURES";
103	}
104	return "OP_UNKNOWN?";
105}
106
107void orangefs_new_tag(struct orangefs_kernel_op_s *op)
108{
109	spin_lock(&next_tag_value_lock);
110	op->tag = next_tag_value++;
111	if (next_tag_value == 0)
112		next_tag_value = 100;
113	spin_unlock(&next_tag_value_lock);
114}
115
116struct orangefs_kernel_op_s *op_alloc(__s32 type)
117{
118	struct orangefs_kernel_op_s *new_op = NULL;
119
120	new_op = kmem_cache_zalloc(op_cache, GFP_KERNEL);
121	if (new_op) {
122		INIT_LIST_HEAD(&new_op->list);
123		spin_lock_init(&new_op->lock);
124		init_completion(&new_op->waitq);
125
126		new_op->upcall.type = ORANGEFS_VFS_OP_INVALID;
127		new_op->downcall.type = ORANGEFS_VFS_OP_INVALID;
128		new_op->downcall.status = -1;
129
130		new_op->op_state = OP_VFS_STATE_UNKNOWN;
131
132		/* initialize the op specific tag and upcall credentials */
133		orangefs_new_tag(new_op);
134		new_op->upcall.type = type;
135		new_op->attempts = 0;
136		gossip_debug(GOSSIP_CACHE_DEBUG,
137			     "Alloced OP (%p: %llu %s)\n",
138			     new_op,
139			     llu(new_op->tag),
140			     get_opname_string(new_op));
141
142		new_op->upcall.uid = from_kuid(&init_user_ns,
143					       current_fsuid());
144
145		new_op->upcall.gid = from_kgid(&init_user_ns,
146					       current_fsgid());
147	} else {
148		gossip_err("op_alloc: kmem_cache_zalloc failed!\n");
149	}
150	return new_op;
151}
152
153void op_release(struct orangefs_kernel_op_s *orangefs_op)
154{
155	if (orangefs_op) {
156		gossip_debug(GOSSIP_CACHE_DEBUG,
157			     "Releasing OP (%p: %llu)\n",
158			     orangefs_op,
159			     llu(orangefs_op->tag));
160		kmem_cache_free(op_cache, orangefs_op);
161	} else {
162		gossip_err("NULL pointer in op_release\n");
163	}
164}
165