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.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2012, Whamcloud, Inc.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/ofd/filter_fmd.c
39 #define DEBUG_SUBSYSTEM S_FILTER
41 #include "ofd_internal.h"
43 static cfs_mem_cache_t *ll_fmd_cachep;
45 /* drop fmd reference, free it if last ref. must be called with fed_lock held.*/
46 static inline void ofd_fmd_put_nolock(struct obd_export *exp,
47 struct ofd_mod_data *fmd)
49 struct filter_export_data *fed = &exp->exp_filter_data;
51 LASSERT_SPIN_LOCKED(&fed->fed_lock);
52 if (--fmd->fmd_refcount == 0) {
53 /* XXX when we have persistent reservations and the handle
54 * is stored herein we need to drop it here. */
56 cfs_list_del(&fmd->fmd_list);
57 OBD_SLAB_FREE(fmd, ll_fmd_cachep, sizeof(*fmd));
61 /* drop fmd reference, free it if last ref */
62 void ofd_fmd_put(struct obd_export *exp, struct ofd_mod_data *fmd)
64 struct filter_export_data *fed = &exp->exp_filter_data;
69 spin_lock(&fed->fed_lock);
70 ofd_fmd_put_nolock(exp, fmd); /* caller reference */
71 spin_unlock(&fed->fed_lock);
74 /* expire entries from the end of the list if there are too many
75 * or they are too old */
76 static void ofd_fmd_expire_nolock(struct obd_export *exp,
77 struct ofd_mod_data *keep)
79 struct filter_export_data *fed = &exp->exp_filter_data;
80 struct ofd_device *ofd = ofd_exp(exp);
81 struct ofd_mod_data *fmd, *tmp;
83 cfs_time_t now = cfs_time_current();
85 cfs_list_for_each_entry_safe(fmd, tmp, &fed->fed_mod_list, fmd_list) {
89 if (cfs_time_before(now, fmd->fmd_expire) &&
90 fed->fed_mod_count < ofd->ofd_fmd_max_num)
93 cfs_list_del_init(&fmd->fmd_list);
94 ofd_fmd_put_nolock(exp, fmd); /* list reference */
98 void ofd_fmd_expire(struct obd_export *exp)
100 struct filter_export_data *fed = &exp->exp_filter_data;
102 spin_lock(&fed->fed_lock);
103 ofd_fmd_expire_nolock(exp, NULL);
104 spin_unlock(&fed->fed_lock);
107 /* find specified fid in fed_fmd_list.
108 * caller must hold fed_lock and take fmd reference itself */
109 static struct ofd_mod_data *ofd_fmd_find_nolock(struct obd_export *exp,
110 const struct lu_fid *fid)
112 struct filter_export_data *fed = &exp->exp_filter_data;
113 struct ofd_mod_data *found = NULL, *fmd;
114 struct ofd_device *ofd = ofd_exp(exp);
116 cfs_time_t now = cfs_time_current();
118 LASSERT_SPIN_LOCKED(&fed->fed_lock);
120 cfs_list_for_each_entry_reverse(fmd, &fed->fed_mod_list, fmd_list) {
121 if (lu_fid_eq(&fmd->fmd_fid, fid)) {
123 cfs_list_del(&fmd->fmd_list);
124 cfs_list_add_tail(&fmd->fmd_list, &fed->fed_mod_list);
125 fmd->fmd_expire = cfs_time_add(now, ofd->ofd_fmd_max_age);
130 ofd_fmd_expire_nolock(exp, found);
135 /* Find fmd based on fid or return NULL if not found. */
136 struct ofd_mod_data *ofd_fmd_find(struct obd_export *exp,
139 struct filter_export_data *fed = &exp->exp_filter_data;
140 struct ofd_mod_data *fmd;
142 spin_lock(&fed->fed_lock);
143 fmd = ofd_fmd_find_nolock(exp, fid);
145 fmd->fmd_refcount++; /* caller reference */
146 spin_unlock(&fed->fed_lock);
151 /* Find fmd based on FID, or create a new one if none is found.
152 * It is possible for this function to return NULL under memory pressure,
153 * or if fid = 0 is passed (which will only cause old entries to expire).
154 * Currently this is not fatal because any fmd state is transient and
155 * may also be freed when it gets sufficiently old. */
156 struct ofd_mod_data *ofd_fmd_get(struct obd_export *exp, struct lu_fid *fid)
158 struct filter_export_data *fed = &exp->exp_filter_data;
159 struct ofd_device *ofd = ofd_exp(exp);
160 struct ofd_mod_data *found = NULL, *fmd_new = NULL;
162 cfs_time_t now = cfs_time_current();
164 OBD_SLAB_ALLOC_PTR(fmd_new, ll_fmd_cachep);
166 spin_lock(&fed->fed_lock);
167 found = ofd_fmd_find_nolock(exp, fid);
170 cfs_list_add_tail(&fmd_new->fmd_list,
172 fmd_new->fmd_fid = *fid;
173 fmd_new->fmd_refcount++; /* list reference */
175 fed->fed_mod_count++;
177 OBD_SLAB_FREE_PTR(fmd_new, ll_fmd_cachep);
181 found->fmd_refcount++; /* caller reference */
182 found->fmd_expire = cfs_time_add(now, ofd->ofd_fmd_max_age);
185 spin_unlock(&fed->fed_lock);
191 /* drop fmd list reference so it will disappear when last reference is put.
192 * This isn't so critical because it would in fact only affect the one client
193 * that is doing the unlink and at worst we have an stale entry referencing
194 * an object that should never be used again. */
195 void ofd_fmd_drop(struct obd_export *exp, struct lu_fid *fid)
197 struct filter_export_data *fed = &exp->exp_filter_data;
198 struct ofd_mod_data *found = NULL;
200 spin_lock(&fed->fed_lock);
201 found = ofd_fmd_find_nolock(exp, fid);
203 cfs_list_del_init(&found->fmd_list);
204 ofd_fmd_put_nolock(exp, found);
206 spin_unlock(&fed->fed_lock);
210 /* remove all entries from fmd list */
211 void ofd_fmd_cleanup(struct obd_export *exp)
213 struct filter_export_data *fed = &exp->exp_filter_data;
214 struct ofd_mod_data *fmd = NULL, *tmp;
216 spin_lock(&fed->fed_lock);
217 cfs_list_for_each_entry_safe(fmd, tmp, &fed->fed_mod_list, fmd_list) {
218 cfs_list_del_init(&fmd->fmd_list);
219 if (fmd->fmd_refcount > 1) {
220 CDEBUG(D_INFO, "fmd %p still referenced (refcount = %d)\n",
221 fmd, fmd->fmd_refcount);
223 ofd_fmd_put_nolock(exp, fmd);
225 spin_unlock(&fed->fed_lock);
228 int ofd_fmd_init(void)
230 ll_fmd_cachep = cfs_mem_cache_create("ll_fmd_cache",
231 sizeof(struct ofd_mod_data),
239 void ofd_fmd_exit(void)
242 int rc = cfs_mem_cache_destroy(ll_fmd_cachep);
244 LASSERTF(rc == 0, "Cannot destroy ll_fmd_cachep: rc %d\n", rc);
245 ll_fmd_cachep = NULL;