xref: /openbmc/linux/fs/ocfs2/sysfile.c (revision bef7a78d)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* -*- mode: c; c-basic-offset: 8; -*-
3  * vim: noexpandtab sw=8 ts=8 sts=0:
4  *
5  * sysfile.c
6  *
7  * Initialize, read, write, etc. system files.
8  *
9  * Copyright (C) 2002, 2004 Oracle.  All rights reserved.
10  */
11 
12 #include <linux/fs.h>
13 #include <linux/types.h>
14 #include <linux/highmem.h>
15 
16 #include <cluster/masklog.h>
17 
18 #include "ocfs2.h"
19 
20 #include "alloc.h"
21 #include "dir.h"
22 #include "inode.h"
23 #include "journal.h"
24 #include "sysfile.h"
25 
26 #include "buffer_head_io.h"
27 
28 static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
29 						   int type,
30 						   u32 slot);
31 
32 #ifdef CONFIG_DEBUG_LOCK_ALLOC
33 static struct lock_class_key ocfs2_sysfile_cluster_lock_key[NUM_SYSTEM_INODES];
34 #endif
35 
36 static inline int is_global_system_inode(int type)
37 {
38 	return type >= OCFS2_FIRST_ONLINE_SYSTEM_INODE &&
39 		type <= OCFS2_LAST_GLOBAL_SYSTEM_INODE;
40 }
41 
42 static struct inode **get_local_system_inode(struct ocfs2_super *osb,
43 					     int type,
44 					     u32 slot)
45 {
46 	int index;
47 	struct inode **local_system_inodes, **free = NULL;
48 
49 	BUG_ON(slot == OCFS2_INVALID_SLOT);
50 	BUG_ON(type < OCFS2_FIRST_LOCAL_SYSTEM_INODE ||
51 	       type > OCFS2_LAST_LOCAL_SYSTEM_INODE);
52 
53 	spin_lock(&osb->osb_lock);
54 	local_system_inodes = osb->local_system_inodes;
55 	spin_unlock(&osb->osb_lock);
56 
57 	if (unlikely(!local_system_inodes)) {
58 		local_system_inodes =
59 			kzalloc(array3_size(sizeof(struct inode *),
60 					    NUM_LOCAL_SYSTEM_INODES,
61 					    osb->max_slots),
62 				GFP_NOFS);
63 		if (!local_system_inodes) {
64 			mlog_errno(-ENOMEM);
65 			/*
66 			 * return NULL here so that ocfs2_get_sytem_file_inodes
67 			 * will try to create an inode and use it. We will try
68 			 * to initialize local_system_inodes next time.
69 			 */
70 			return NULL;
71 		}
72 
73 		spin_lock(&osb->osb_lock);
74 		if (osb->local_system_inodes) {
75 			/* Someone has initialized it for us. */
76 			free = local_system_inodes;
77 			local_system_inodes = osb->local_system_inodes;
78 		} else
79 			osb->local_system_inodes = local_system_inodes;
80 		spin_unlock(&osb->osb_lock);
81 		kfree(free);
82 	}
83 
84 	index = (slot * NUM_LOCAL_SYSTEM_INODES) +
85 		(type - OCFS2_FIRST_LOCAL_SYSTEM_INODE);
86 
87 	return &local_system_inodes[index];
88 }
89 
90 struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
91 					  int type,
92 					  u32 slot)
93 {
94 	struct inode *inode = NULL;
95 	struct inode **arr = NULL;
96 
97 	/* avoid the lookup if cached in local system file array */
98 	if (is_global_system_inode(type)) {
99 		arr = &(osb->global_system_inodes[type]);
100 	} else
101 		arr = get_local_system_inode(osb, type, slot);
102 
103 	mutex_lock(&osb->system_file_mutex);
104 	if (arr && ((inode = *arr) != NULL)) {
105 		/* get a ref in addition to the array ref */
106 		inode = igrab(inode);
107 		mutex_unlock(&osb->system_file_mutex);
108 		BUG_ON(!inode);
109 
110 		return inode;
111 	}
112 
113 	/* this gets one ref thru iget */
114 	inode = _ocfs2_get_system_file_inode(osb, type, slot);
115 
116 	/* add one more if putting into array for first time */
117 	if (arr && inode) {
118 		*arr = igrab(inode);
119 		BUG_ON(!*arr);
120 	}
121 	mutex_unlock(&osb->system_file_mutex);
122 	return inode;
123 }
124 
125 static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
126 						   int type,
127 						   u32 slot)
128 {
129 	char namebuf[40];
130 	struct inode *inode = NULL;
131 	u64 blkno;
132 	int status = 0;
133 
134 	ocfs2_sprintf_system_inode_name(namebuf,
135 					sizeof(namebuf),
136 					type, slot);
137 
138 	status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,
139 					    strlen(namebuf), &blkno);
140 	if (status < 0) {
141 		goto bail;
142 	}
143 
144 	inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE, type);
145 	if (IS_ERR(inode)) {
146 		mlog_errno(PTR_ERR(inode));
147 		inode = NULL;
148 		goto bail;
149 	}
150 #ifdef CONFIG_DEBUG_LOCK_ALLOC
151 	if (type == LOCAL_USER_QUOTA_SYSTEM_INODE ||
152 	    type == LOCAL_GROUP_QUOTA_SYSTEM_INODE ||
153 	    type == JOURNAL_SYSTEM_INODE) {
154 		/* Ignore inode lock on these inodes as the lock does not
155 		 * really belong to any process and lockdep cannot handle
156 		 * that */
157 		OCFS2_I(inode)->ip_inode_lockres.l_lockdep_map.key = NULL;
158 	} else {
159 		lockdep_init_map(&OCFS2_I(inode)->ip_inode_lockres.
160 								l_lockdep_map,
161 				 ocfs2_system_inodes[type].si_name,
162 				 &ocfs2_sysfile_cluster_lock_key[type], 0);
163 	}
164 #endif
165 bail:
166 
167 	return inode;
168 }
169 
170