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 struct ofd_mod_data *fmd, *tmp;
118 cfs_time_t now = cfs_time_current();
120 list_for_each_entry_safe(fmd, tmp, &fed->fed_mod_list, fmd_list) {
124 if (cfs_time_before(now, fmd->fmd_expire) &&
125 fed->fed_mod_count < ofd->ofd_fmd_max_num)
128 list_del_init(&fmd->fmd_list);
129 ofd_fmd_put_nolock(exp, fmd); /* list reference */
134 * Expire FMD entries.
136 * This is a wrapper to call ofd_fmd_expire_nolock() with the required lock.
138 * \param[in] exp OBD export
140 void ofd_fmd_expire(struct obd_export *exp)
142 struct filter_export_data *fed = &exp->exp_filter_data;
144 spin_lock(&fed->fed_lock);
145 ofd_fmd_expire_nolock(exp, NULL);
146 spin_unlock(&fed->fed_lock);
150 * Find FMD by specified FID.
152 * Function finds FMD entry by FID in the filter_export_data::fed_fmd_list.
154 * Caller must hold filter_export_data::fed_lock and take FMD reference.
156 * \param[in] exp OBD export
157 * \param[in] fid FID of FMD to find
159 * \retval struct ofd_mod_data found by FID
160 * \retval NULL is FMD is not found
162 static struct ofd_mod_data *ofd_fmd_find_nolock(struct obd_export *exp,
163 const struct lu_fid *fid)
165 struct filter_export_data *fed = &exp->exp_filter_data;
166 struct ofd_mod_data *found = NULL, *fmd;
167 struct ofd_device *ofd = ofd_exp(exp);
169 cfs_time_t now = cfs_time_current();
171 assert_spin_locked(&fed->fed_lock);
173 list_for_each_entry_reverse(fmd, &fed->fed_mod_list, fmd_list) {
174 if (lu_fid_eq(&fmd->fmd_fid, fid)) {
176 list_del(&fmd->fmd_list);
177 list_add_tail(&fmd->fmd_list, &fed->fed_mod_list);
178 fmd->fmd_expire = cfs_time_add(now, ofd->ofd_fmd_max_age);
183 ofd_fmd_expire_nolock(exp, found);
189 * Find FMD by specified FID with locking.
191 * Wrapper to the ofd_fmd_find_nolock() with correct locks.
193 * \param[in] exp OBD export
194 * \param[in] fid FID of FMD to find
196 * \retval struct ofd_mod_data found by FID
197 * \retval NULL indicates FMD is not found
199 struct ofd_mod_data *ofd_fmd_find(struct obd_export *exp,
200 const struct lu_fid *fid)
202 struct filter_export_data *fed = &exp->exp_filter_data;
203 struct ofd_mod_data *fmd;
205 spin_lock(&fed->fed_lock);
206 fmd = ofd_fmd_find_nolock(exp, fid);
208 fmd->fmd_refcount++; /* caller reference */
209 spin_unlock(&fed->fed_lock);
215 * Find FMD by FID or create a new one if none is found.
217 * It is possible for this function to return NULL under memory pressure,
218 * or if the passed FID is zero (which will only cause old entries to expire).
219 * Currently this is not fatal because any FMD state is transient and
220 * may also be freed when it gets sufficiently old.
222 * \param[in] exp OBD export
223 * \param[in] fid FID of FMD to find
225 * \retval struct ofd_mod_data found by FID
226 * \retval NULL indicates FMD is not found
228 struct ofd_mod_data *ofd_fmd_get(struct obd_export *exp, const struct lu_fid *fid)
230 struct filter_export_data *fed = &exp->exp_filter_data;
231 struct ofd_device *ofd = ofd_exp(exp);
232 struct ofd_mod_data *found = NULL, *fmd_new = NULL;
234 cfs_time_t now = cfs_time_current();
236 OBD_SLAB_ALLOC_PTR(fmd_new, ll_fmd_cachep);
238 spin_lock(&fed->fed_lock);
239 found = ofd_fmd_find_nolock(exp, fid);
242 list_add_tail(&fmd_new->fmd_list,
244 fmd_new->fmd_fid = *fid;
245 fmd_new->fmd_refcount++; /* list reference */
247 fed->fed_mod_count++;
249 OBD_SLAB_FREE_PTR(fmd_new, ll_fmd_cachep);
253 found->fmd_refcount++; /* caller reference */
254 found->fmd_expire = cfs_time_add(now, ofd->ofd_fmd_max_age);
257 spin_unlock(&fed->fed_lock);
264 * Drop FMD list reference so it will disappear when last reference is dropped
267 * This function is called from ofd_destroy() and may only affect
268 * the one client that is doing the unlink and at worst we have an stale entry
269 * referencing an object that should never be used again.
271 * NB: this function is used only if DO_FMD_DROP is defined. It is not
272 * currently defined, so FMD drop doesn't happen and FMD are dropped only
275 * \param[in] exp OBD export
276 * \param[in] fid FID of FMD to drop
278 void ofd_fmd_drop(struct obd_export *exp, const struct lu_fid *fid)
280 struct filter_export_data *fed = &exp->exp_filter_data;
281 struct ofd_mod_data *found = NULL;
283 spin_lock(&fed->fed_lock);
284 found = ofd_fmd_find_nolock(exp, fid);
286 list_del_init(&found->fmd_list);
287 ofd_fmd_put_nolock(exp, found);
289 spin_unlock(&fed->fed_lock);
294 * Remove all entries from FMD list.
296 * Cleanup function to free all FMD enries on the given export.
298 * \param[in] exp OBD export
300 void ofd_fmd_cleanup(struct obd_export *exp)
302 struct filter_export_data *fed = &exp->exp_filter_data;
303 struct ofd_mod_data *fmd = NULL, *tmp;
305 spin_lock(&fed->fed_lock);
306 list_for_each_entry_safe(fmd, tmp, &fed->fed_mod_list, fmd_list) {
307 list_del_init(&fmd->fmd_list);
308 if (fmd->fmd_refcount > 1) {
309 CDEBUG(D_INFO, "fmd %p still referenced (refcount = %d)\n",
310 fmd, fmd->fmd_refcount);
312 ofd_fmd_put_nolock(exp, fmd);
314 spin_unlock(&fed->fed_lock);
318 * Initialize FMD subsystem.
320 * This function is called upon OFD setup and initialize memory to be used
323 int ofd_fmd_init(void)
325 ll_fmd_cachep = kmem_cache_create("ll_fmd_cache",
326 sizeof(struct ofd_mod_data),
335 * Stop FMD subsystem.
337 * This function is called upon OFD cleanup and destroy memory used
340 void ofd_fmd_exit(void)
343 kmem_cache_destroy(ll_fmd_cachep);
344 ll_fmd_cachep = NULL;