4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
24 * Use is subject to license terms.
26 * Copyright (c) 2012, 2015, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * lustre/ofd/ofd_fmd.c
34 * This file provides functions to handle Filter Modification Data (FMD).
35 * The FMD is responsible for file attributes to be applied in
36 * Transaction ID (XID) order, so older requests can't re-write newer
39 * FMD is organized as per-client list and identified by FID of object. Each
40 * FMD stores FID of object and the highest received XID of modification
41 * request for this object.
43 * FMD can expire if there are no updates for a long time to keep the list
46 * Author: Andreas Dilger <andreas.dilger@intel.com>
49 #define DEBUG_SUBSYSTEM S_FILTER
51 #include "ofd_internal.h"
53 static struct kmem_cache *ll_fmd_cachep;
56 * Drop FMD reference and free it if reference drops to zero.
58 * Must be called with fed_lock held.
60 * \param[in] exp OBD export
61 * \param[in] fmd FMD to put
63 static inline void ofd_fmd_put_nolock(struct obd_export *exp,
64 struct ofd_mod_data *fmd)
66 struct filter_export_data *fed = &exp->exp_filter_data;
68 assert_spin_locked(&fed->fed_lock);
69 if (--fmd->fmd_refcount == 0) {
70 /* XXX when we have persistent reservations and the handle
71 * is stored herein we need to drop it here. */
73 list_del(&fmd->fmd_list);
74 OBD_SLAB_FREE(fmd, ll_fmd_cachep, sizeof(*fmd));
79 * Wrapper to drop FMD reference with fed_lock held.
81 * \param[in] exp OBD export
82 * \param[in] fmd FMD to put
84 void ofd_fmd_put(struct obd_export *exp, struct ofd_mod_data *fmd)
86 struct filter_export_data *fed = &exp->exp_filter_data;
91 spin_lock(&fed->fed_lock);
92 ofd_fmd_put_nolock(exp, fmd); /* caller reference */
93 spin_unlock(&fed->fed_lock);
99 * Expire entries from the FMD list if there are too many
100 * of them or they are too old.
102 * This function must be called with fed_lock held.
104 * The \a keep FMD is not to be expired in any case. This parameter is used
105 * by ofd_fmd_find_nolock() to prohibit a FMD that was just found from
108 * \param[in] exp OBD export
109 * \param[in] keep FMD to keep always
111 static void ofd_fmd_expire_nolock(struct obd_export *exp,
112 struct ofd_mod_data *keep)
114 struct filter_export_data *fed = &exp->exp_filter_data;
115 struct ofd_device *ofd = ofd_exp(exp);
116 time64_t now = ktime_get_seconds();
117 struct ofd_mod_data *fmd, *tmp;
119 list_for_each_entry_safe(fmd, tmp, &fed->fed_mod_list, fmd_list) {
123 if (now < fmd->fmd_expire &&
124 fed->fed_mod_count < ofd->ofd_fmd_max_num)
127 list_del_init(&fmd->fmd_list);
128 ofd_fmd_put_nolock(exp, fmd); /* list reference */
133 * Expire FMD entries.
135 * This is a wrapper to call ofd_fmd_expire_nolock() with the required lock.
137 * \param[in] exp OBD export
139 void ofd_fmd_expire(struct obd_export *exp)
141 struct filter_export_data *fed = &exp->exp_filter_data;
143 spin_lock(&fed->fed_lock);
144 ofd_fmd_expire_nolock(exp, NULL);
145 spin_unlock(&fed->fed_lock);
149 * Find FMD by specified FID.
151 * Function finds FMD entry by FID in the filter_export_data::fed_fmd_list.
153 * Caller must hold filter_export_data::fed_lock and take FMD reference.
155 * \param[in] exp OBD export
156 * \param[in] fid FID of FMD to find
158 * \retval struct ofd_mod_data found by FID
159 * \retval NULL is FMD is not found
161 static struct ofd_mod_data *ofd_fmd_find_nolock(struct obd_export *exp,
162 const struct lu_fid *fid)
164 struct filter_export_data *fed = &exp->exp_filter_data;
165 struct ofd_mod_data *found = NULL, *fmd;
166 struct ofd_device *ofd = ofd_exp(exp);
167 time64_t now = ktime_get_seconds();
169 assert_spin_locked(&fed->fed_lock);
171 list_for_each_entry_reverse(fmd, &fed->fed_mod_list, fmd_list) {
172 if (lu_fid_eq(&fmd->fmd_fid, fid)) {
174 list_del(&fmd->fmd_list);
175 list_add_tail(&fmd->fmd_list, &fed->fed_mod_list);
176 fmd->fmd_expire = now + ofd->ofd_fmd_max_age;
181 ofd_fmd_expire_nolock(exp, found);
187 * Find FMD by specified FID with locking.
189 * Wrapper to the ofd_fmd_find_nolock() with correct locks.
191 * \param[in] exp OBD export
192 * \param[in] fid FID of FMD to find
194 * \retval struct ofd_mod_data found by FID
195 * \retval NULL indicates FMD is not found
197 struct ofd_mod_data *ofd_fmd_find(struct obd_export *exp,
198 const struct lu_fid *fid)
200 struct filter_export_data *fed = &exp->exp_filter_data;
201 struct ofd_mod_data *fmd;
203 spin_lock(&fed->fed_lock);
204 fmd = ofd_fmd_find_nolock(exp, fid);
206 fmd->fmd_refcount++; /* caller reference */
207 spin_unlock(&fed->fed_lock);
213 * Find FMD by FID or create a new one if none is found.
215 * It is possible for this function to return NULL under memory pressure,
216 * or if the passed FID is zero (which will only cause old entries to expire).
217 * Currently this is not fatal because any FMD state is transient and
218 * may also be freed when it gets sufficiently old.
220 * \param[in] exp OBD export
221 * \param[in] fid FID of FMD to find
223 * \retval struct ofd_mod_data found by FID
224 * \retval NULL indicates FMD is not found
226 struct ofd_mod_data *ofd_fmd_get(struct obd_export *exp, const struct lu_fid *fid)
228 struct filter_export_data *fed = &exp->exp_filter_data;
229 struct ofd_device *ofd = ofd_exp(exp);
230 struct ofd_mod_data *found = NULL, *fmd_new = NULL;
231 time64_t now = ktime_get_seconds();
233 OBD_SLAB_ALLOC_PTR(fmd_new, ll_fmd_cachep);
235 spin_lock(&fed->fed_lock);
236 found = ofd_fmd_find_nolock(exp, fid);
239 list_add_tail(&fmd_new->fmd_list,
241 fmd_new->fmd_fid = *fid;
242 fmd_new->fmd_refcount++; /* list reference */
244 fed->fed_mod_count++;
246 OBD_SLAB_FREE_PTR(fmd_new, ll_fmd_cachep);
250 found->fmd_refcount++; /* caller reference */
251 found->fmd_expire = now + ofd->ofd_fmd_max_age;
254 spin_unlock(&fed->fed_lock);
261 * Drop FMD list reference so it will disappear when last reference is dropped
264 * This function is called from ofd_destroy() and may only affect
265 * the one client that is doing the unlink and at worst we have an stale entry
266 * referencing an object that should never be used again.
268 * NB: this function is used only if DO_FMD_DROP is defined. It is not
269 * currently defined, so FMD drop doesn't happen and FMD are dropped only
272 * \param[in] exp OBD export
273 * \param[in] fid FID of FMD to drop
275 void ofd_fmd_drop(struct obd_export *exp, const struct lu_fid *fid)
277 struct filter_export_data *fed = &exp->exp_filter_data;
278 struct ofd_mod_data *found = NULL;
280 spin_lock(&fed->fed_lock);
281 found = ofd_fmd_find_nolock(exp, fid);
283 list_del_init(&found->fmd_list);
284 ofd_fmd_put_nolock(exp, found);
286 spin_unlock(&fed->fed_lock);
291 * Remove all entries from FMD list.
293 * Cleanup function to free all FMD enries on the given export.
295 * \param[in] exp OBD export
297 void ofd_fmd_cleanup(struct obd_export *exp)
299 struct filter_export_data *fed = &exp->exp_filter_data;
300 struct ofd_mod_data *fmd = NULL, *tmp;
302 spin_lock(&fed->fed_lock);
303 list_for_each_entry_safe(fmd, tmp, &fed->fed_mod_list, fmd_list) {
304 list_del_init(&fmd->fmd_list);
305 if (fmd->fmd_refcount > 1) {
306 CDEBUG(D_INFO, "fmd %p still referenced (refcount = %d)\n",
307 fmd, fmd->fmd_refcount);
309 ofd_fmd_put_nolock(exp, fmd);
311 spin_unlock(&fed->fed_lock);
315 * Initialize FMD subsystem.
317 * This function is called upon OFD setup and initialize memory to be used
320 int ofd_fmd_init(void)
322 ll_fmd_cachep = kmem_cache_create("ll_fmd_cache",
323 sizeof(struct ofd_mod_data),
332 * Stop FMD subsystem.
334 * This function is called upon OFD cleanup and destroy memory used
337 void ofd_fmd_exit(void)
340 kmem_cache_destroy(ll_fmd_cachep);
341 ll_fmd_cachep = NULL;