Blame view

fs/xfs/xfs_filestream.c 11.2 KB
2a82b8be8   David Chinner   [XFS] Concurrent ...
1
2
  /*
   * Copyright (c) 2006-2007 Silicon Graphics, Inc.
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
3
   * Copyright (c) 2014 Christoph Hellwig.
2a82b8be8   David Chinner   [XFS] Concurrent ...
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   * All Rights Reserved.
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it would be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write the Free Software Foundation,
   * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   */
  #include "xfs.h"
a4fbe6ab1   Dave Chinner   xfs: decouple ino...
20
  #include "xfs_format.h"
239880ef6   Dave Chinner   xfs: decouple log...
21
22
  #include "xfs_log_format.h"
  #include "xfs_trans_resv.h"
239880ef6   Dave Chinner   xfs: decouple log...
23
24
  #include "xfs_sb.h"
  #include "xfs_mount.h"
3ab78df2a   Darrick J. Wong   xfs: rework xfs_b...
25
  #include "xfs_defer.h"
2a82b8be8   David Chinner   [XFS] Concurrent ...
26
  #include "xfs_inode.h"
2a82b8be8   David Chinner   [XFS] Concurrent ...
27
  #include "xfs_bmap.h"
689881145   Dave Chinner   xfs: create xfs_b...
28
  #include "xfs_bmap_util.h"
2a82b8be8   David Chinner   [XFS] Concurrent ...
29
  #include "xfs_alloc.h"
2a82b8be8   David Chinner   [XFS] Concurrent ...
30
31
  #include "xfs_mru_cache.h"
  #include "xfs_filestream.h"
0b1b213fc   Christoph Hellwig   xfs: event tracin...
32
  #include "xfs_trace.h"
3fd129b63   Darrick J. Wong   xfs: set up per-A...
33
  #include "xfs_ag_resv.h"
2a82b8be8   David Chinner   [XFS] Concurrent ...
34

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
35
36
37
38
39
40
41
42
43
44
  struct xfs_fstrm_item {
  	struct xfs_mru_cache_elem	mru;
  	struct xfs_inode		*ip;
  	xfs_agnumber_t			ag; /* AG in use for this directory */
  };
  
  enum xfs_fstrm_alloc {
  	XFS_PICK_USERDATA = 1,
  	XFS_PICK_LOWSPACE = 2,
  };
2a82b8be8   David Chinner   [XFS] Concurrent ...
45

0664ce8d0   Christoph Hellwig   xfs: clean up fil...
46
47
  /*
   * Allocation group filestream associations are tracked with per-ag atomic
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
48
   * counters.  These counters allow xfs_filestream_pick_ag() to tell whether a
0664ce8d0   Christoph Hellwig   xfs: clean up fil...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
   * particular AG already has active filestreams associated with it. The mount
   * point's m_peraglock is used to protect these counters from per-ag array
   * re-allocation during a growfs operation.  When xfs_growfs_data_private() is
   * about to reallocate the array, it calls xfs_filestream_flush() with the
   * m_peraglock held in write mode.
   *
   * Since xfs_mru_cache_flush() guarantees that all the free functions for all
   * the cache elements have finished executing before it returns, it's safe for
   * the free functions to use the atomic counters without m_peraglock protection.
   * This allows the implementation of xfs_fstrm_free_func() to be agnostic about
   * whether it was called with the m_peraglock held in read mode, write mode or
   * not held at all.  The race condition this addresses is the following:
   *
   *  - The work queue scheduler fires and pulls a filestream directory cache
   *    element off the LRU end of the cache for deletion, then gets pre-empted.
   *  - A growfs operation grabs the m_peraglock in write mode, flushes all the
   *    remaining items from the cache and reallocates the mount point's per-ag
   *    array, resetting all the counters to zero.
   *  - The work queue thread resumes and calls the free function for the element
   *    it started cleaning up earlier.  In the process it decrements the
   *    filestreams counter for an AG that now has no references.
   *
   * With a shrinkfs feature, the above scenario could panic the system.
   *
   * All other uses of the following macros should be protected by either the
   * m_peraglock held in read mode, or the cache's internal locking exposed by the
   * interval between a call to xfs_mru_cache_lookup() and a call to
   * xfs_mru_cache_done().  In addition, the m_peraglock must be held in read mode
   * when new elements are added to the cache.
   *
   * Combined, these locking rules ensure that no associations will ever exist in
   * the cache that reference per-ag array elements that have since been
   * reallocated.
   */
b94acd478   Christoph Hellwig   xfs: add filestre...
83
  int
0664ce8d0   Christoph Hellwig   xfs: clean up fil...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  xfs_filestream_peek_ag(
  	xfs_mount_t	*mp,
  	xfs_agnumber_t	agno)
  {
  	struct xfs_perag *pag;
  	int		ret;
  
  	pag = xfs_perag_get(mp, agno);
  	ret = atomic_read(&pag->pagf_fstrms);
  	xfs_perag_put(pag);
  	return ret;
  }
  
  static int
  xfs_filestream_get_ag(
  	xfs_mount_t	*mp,
  	xfs_agnumber_t	agno)
  {
  	struct xfs_perag *pag;
  	int		ret;
  
  	pag = xfs_perag_get(mp, agno);
  	ret = atomic_inc_return(&pag->pagf_fstrms);
  	xfs_perag_put(pag);
  	return ret;
  }
  
  static void
  xfs_filestream_put_ag(
  	xfs_mount_t	*mp,
  	xfs_agnumber_t	agno)
  {
  	struct xfs_perag *pag;
  
  	pag = xfs_perag_get(mp, agno);
  	atomic_dec(&pag->pagf_fstrms);
  	xfs_perag_put(pag);
  }
2a82b8be8   David Chinner   [XFS] Concurrent ...
122

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
123
124
125
126
127
128
129
130
  static void
  xfs_fstrm_free_func(
  	struct xfs_mru_cache_elem *mru)
  {
  	struct xfs_fstrm_item	*item =
  		container_of(mru, struct xfs_fstrm_item, mru);
  
  	xfs_filestream_put_ag(item->ip->i_mount, item->ag);
b94acd478   Christoph Hellwig   xfs: add filestre...
131
  	trace_xfs_filestream_free(item->ip, item->ag);
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
132

1919adda0   Christoph Hellwig   xfs: don't create...
133
  	kmem_free(item);
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
134
  }
2a82b8be8   David Chinner   [XFS] Concurrent ...
135
136
137
138
139
  /*
   * Scan the AGs starting at startag looking for an AG that isn't in use and has
   * at least minlen blocks free.
   */
  static int
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
140
141
142
143
144
145
  xfs_filestream_pick_ag(
  	struct xfs_inode	*ip,
  	xfs_agnumber_t		startag,
  	xfs_agnumber_t		*agp,
  	int			flags,
  	xfs_extlen_t		minlen)
2a82b8be8   David Chinner   [XFS] Concurrent ...
146
  {
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
147
148
149
  	struct xfs_mount	*mp = ip->i_mount;
  	struct xfs_fstrm_item	*item;
  	struct xfs_perag	*pag;
b94acd478   Christoph Hellwig   xfs: add filestre...
150
  	xfs_extlen_t		longest, free = 0, minfree, maxfree = 0;
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
151
  	xfs_agnumber_t		ag, max_ag = NULLAGNUMBER;
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
152
  	int			err, trylock, nscan;
c19b3b05a   Dave Chinner   xfs: mode di_mode...
153
  	ASSERT(S_ISDIR(VFS_I(ip)->i_mode));
2a82b8be8   David Chinner   [XFS] Concurrent ...
154
155
156
157
158
159
160
161
162
163
164
  
  	/* 2% of an AG's blocks must be free for it to be chosen. */
  	minfree = mp->m_sb.sb_agblocks / 50;
  
  	ag = startag;
  	*agp = NULLAGNUMBER;
  
  	/* For the first pass, don't sleep trying to init the per-AG. */
  	trylock = XFS_ALLOC_FLAG_TRYLOCK;
  
  	for (nscan = 0; 1; nscan++) {
b94acd478   Christoph Hellwig   xfs: add filestre...
165
  		trace_xfs_filestream_scan(ip, ag);
4196ac08c   Dave Chinner   xfs: Convert file...
166
  		pag = xfs_perag_get(mp, ag);
2a82b8be8   David Chinner   [XFS] Concurrent ...
167
168
169
  
  		if (!pag->pagf_init) {
  			err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);
4196ac08c   Dave Chinner   xfs: Convert file...
170
171
  			if (err && !trylock) {
  				xfs_perag_put(pag);
2a82b8be8   David Chinner   [XFS] Concurrent ...
172
  				return err;
4196ac08c   Dave Chinner   xfs: Convert file...
173
  			}
2a82b8be8   David Chinner   [XFS] Concurrent ...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  		}
  
  		/* Might fail sometimes during the 1st pass with trylock set. */
  		if (!pag->pagf_init)
  			goto next_ag;
  
  		/* Keep track of the AG with the most free blocks. */
  		if (pag->pagf_freeblks > maxfree) {
  			maxfree = pag->pagf_freeblks;
  			max_ag = ag;
  		}
  
  		/*
  		 * The AG reference count does two things: it enforces mutual
  		 * exclusion when examining the suitability of an AG in this
  		 * loop, and it guards against two filestreams being established
  		 * in the same AG as each other.
  		 */
  		if (xfs_filestream_get_ag(mp, ag) > 1) {
  			xfs_filestream_put_ag(mp, ag);
  			goto next_ag;
  		}
50adbcb4c   Dave Chinner   xfs: xfs_alloc_fi...
196
  		longest = xfs_alloc_longest_free_extent(mp, pag,
3fd129b63   Darrick J. Wong   xfs: set up per-A...
197
198
  				xfs_alloc_min_freelist(mp, pag),
  				xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE));
2a82b8be8   David Chinner   [XFS] Concurrent ...
199
200
201
202
203
204
205
  		if (((minlen && longest >= minlen) ||
  		     (!minlen && pag->pagf_freeblks >= minfree)) &&
  		    (!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) ||
  		     (flags & XFS_PICK_LOWSPACE))) {
  
  			/* Break out, retaining the reference on the AG. */
  			free = pag->pagf_freeblks;
4196ac08c   Dave Chinner   xfs: Convert file...
206
  			xfs_perag_put(pag);
2a82b8be8   David Chinner   [XFS] Concurrent ...
207
208
209
210
211
212
213
  			*agp = ag;
  			break;
  		}
  
  		/* Drop the reference on this AG, it's not usable. */
  		xfs_filestream_put_ag(mp, ag);
  next_ag:
4196ac08c   Dave Chinner   xfs: Convert file...
214
  		xfs_perag_put(pag);
2a82b8be8   David Chinner   [XFS] Concurrent ...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  		/* Move to the next AG, wrapping to AG 0 if necessary. */
  		if (++ag >= mp->m_sb.sb_agcount)
  			ag = 0;
  
  		/* If a full pass of the AGs hasn't been done yet, continue. */
  		if (ag != startag)
  			continue;
  
  		/* Allow sleeping in xfs_alloc_pagf_init() on the 2nd pass. */
  		if (trylock != 0) {
  			trylock = 0;
  			continue;
  		}
  
  		/* Finally, if lowspace wasn't set, set it for the 3rd pass. */
  		if (!(flags & XFS_PICK_LOWSPACE)) {
  			flags |= XFS_PICK_LOWSPACE;
  			continue;
  		}
  
  		/*
  		 * Take the AG with the most free space, regardless of whether
  		 * it's already in use by another filestream.
  		 */
  		if (max_ag != NULLAGNUMBER) {
  			xfs_filestream_get_ag(mp, max_ag);
2a82b8be8   David Chinner   [XFS] Concurrent ...
241
242
243
244
245
246
  			free = maxfree;
  			*agp = max_ag;
  			break;
  		}
  
  		/* take AG 0 if none matched */
b94acd478   Christoph Hellwig   xfs: add filestre...
247
  		trace_xfs_filestream_pick(ip, *agp, free, nscan);
2a82b8be8   David Chinner   [XFS] Concurrent ...
248
249
250
  		*agp = 0;
  		return 0;
  	}
b94acd478   Christoph Hellwig   xfs: add filestre...
251
  	trace_xfs_filestream_pick(ip, *agp, free, nscan);
2a82b8be8   David Chinner   [XFS] Concurrent ...
252

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
253
  	if (*agp == NULLAGNUMBER)
2a82b8be8   David Chinner   [XFS] Concurrent ...
254
  		return 0;
2a82b8be8   David Chinner   [XFS] Concurrent ...
255

2451337dd   Dave Chinner   xfs: global error...
256
  	err = -ENOMEM;
1919adda0   Christoph Hellwig   xfs: don't create...
257
  	item = kmem_alloc(sizeof(*item), KM_MAYFAIL);
2a82b8be8   David Chinner   [XFS] Concurrent ...
258
  	if (!item)
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
259
  		goto out_put_ag;
2a82b8be8   David Chinner   [XFS] Concurrent ...
260

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
261
  	item->ag = *agp;
2a82b8be8   David Chinner   [XFS] Concurrent ...
262
  	item->ip = ip;
2a82b8be8   David Chinner   [XFS] Concurrent ...
263

22328d712   Christoph Hellwig   xfs: embedd mru_e...
264
  	err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru);
2a82b8be8   David Chinner   [XFS] Concurrent ...
265
  	if (err) {
2451337dd   Dave Chinner   xfs: global error...
266
  		if (err == -EEXIST)
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
267
268
  			err = 0;
  		goto out_free_item;
2a82b8be8   David Chinner   [XFS] Concurrent ...
269
  	}
2a82b8be8   David Chinner   [XFS] Concurrent ...
270
  	return 0;
2a82b8be8   David Chinner   [XFS] Concurrent ...
271

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
272
  out_free_item:
1919adda0   Christoph Hellwig   xfs: don't create...
273
  	kmem_free(item);
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
274
275
276
  out_put_ag:
  	xfs_filestream_put_ag(mp, *agp);
  	return err;
2a82b8be8   David Chinner   [XFS] Concurrent ...
277
  }
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
278
279
280
  static struct xfs_inode *
  xfs_filestream_get_parent(
  	struct xfs_inode	*ip)
2a82b8be8   David Chinner   [XFS] Concurrent ...
281
  {
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
282
283
  	struct inode		*inode = VFS_I(ip), *dir = NULL;
  	struct dentry		*dentry, *parent;
2a82b8be8   David Chinner   [XFS] Concurrent ...
284

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
285
286
287
  	dentry = d_find_alias(inode);
  	if (!dentry)
  		goto out;
2a82b8be8   David Chinner   [XFS] Concurrent ...
288

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
289
290
291
  	parent = dget_parent(dentry);
  	if (!parent)
  		goto out_dput;
2a82b8be8   David Chinner   [XFS] Concurrent ...
292

2b0143b5c   David Howells   VFS: normal files...
293
  	dir = igrab(d_inode(parent));
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
294
  	dput(parent);
2a82b8be8   David Chinner   [XFS] Concurrent ...
295

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
296
297
298
299
  out_dput:
  	dput(dentry);
  out:
  	return dir ? XFS_I(dir) : NULL;
2a82b8be8   David Chinner   [XFS] Concurrent ...
300
301
302
  }
  
  /*
3b8d90766   Christoph Hellwig   xfs: remove xfs_f...
303
304
305
306
   * Find the right allocation group for a file, either by finding an
   * existing file stream or creating a new one.
   *
   * Returns NULLAGNUMBER in case of an error.
2a82b8be8   David Chinner   [XFS] Concurrent ...
307
308
309
   */
  xfs_agnumber_t
  xfs_filestream_lookup_ag(
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
310
  	struct xfs_inode	*ip)
2a82b8be8   David Chinner   [XFS] Concurrent ...
311
  {
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
312
  	struct xfs_mount	*mp = ip->i_mount;
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
313
  	struct xfs_inode	*pip = NULL;
3b8d90766   Christoph Hellwig   xfs: remove xfs_f...
314
  	xfs_agnumber_t		startag, ag = NULLAGNUMBER;
22328d712   Christoph Hellwig   xfs: embedd mru_e...
315
  	struct xfs_mru_cache_elem *mru;
2a82b8be8   David Chinner   [XFS] Concurrent ...
316

c19b3b05a   Dave Chinner   xfs: mode di_mode...
317
  	ASSERT(S_ISREG(VFS_I(ip)->i_mode));
2a82b8be8   David Chinner   [XFS] Concurrent ...
318

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
319
320
  	pip = xfs_filestream_get_parent(ip);
  	if (!pip)
b26384dc5   Eric Sandeen   xfs: fix NULL poi...
321
  		return NULLAGNUMBER;
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
322
323
  
  	mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
22328d712   Christoph Hellwig   xfs: embedd mru_e...
324
  	if (mru) {
3b8d90766   Christoph Hellwig   xfs: remove xfs_f...
325
  		ag = container_of(mru, struct xfs_fstrm_item, mru)->ag;
22328d712   Christoph Hellwig   xfs: embedd mru_e...
326
  		xfs_mru_cache_done(mp->m_filestream);
3b8d90766   Christoph Hellwig   xfs: remove xfs_f...
327

b94acd478   Christoph Hellwig   xfs: add filestre...
328
  		trace_xfs_filestream_lookup(ip, ag);
3b8d90766   Christoph Hellwig   xfs: remove xfs_f...
329
  		goto out;
2a82b8be8   David Chinner   [XFS] Concurrent ...
330
331
332
333
334
335
336
  	}
  
  	/*
  	 * Set the starting AG using the rotor for inode32, otherwise
  	 * use the directory inode's AG.
  	 */
  	if (mp->m_flags & XFS_MOUNT_32BITINODES) {
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
337
  		xfs_agnumber_t	 rotorstep = xfs_rotorstep;
2a82b8be8   David Chinner   [XFS] Concurrent ...
338
339
340
341
342
  		startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount;
  		mp->m_agfrotor = (mp->m_agfrotor + 1) %
  		                 (mp->m_sb.sb_agcount * rotorstep);
  	} else
  		startag = XFS_INO_TO_AGNO(mp, pip->i_ino);
3b8d90766   Christoph Hellwig   xfs: remove xfs_f...
343
344
345
346
347
  	if (xfs_filestream_pick_ag(pip, startag, &ag, 0, 0))
  		ag = NULLAGNUMBER;
  out:
  	IRELE(pip);
  	return ag;
2a82b8be8   David Chinner   [XFS] Concurrent ...
348
349
350
  }
  
  /*
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
351
352
353
354
   * Pick a new allocation group for the current file and its file stream.
   *
   * This is called when the allocator can't find a suitable extent in the
   * current AG, and we have to move the stream into a new AG with more space.
2a82b8be8   David Chinner   [XFS] Concurrent ...
355
356
357
   */
  int
  xfs_filestream_new_ag(
689881145   Dave Chinner   xfs: create xfs_b...
358
359
  	struct xfs_bmalloca	*ap,
  	xfs_agnumber_t		*agp)
2a82b8be8   David Chinner   [XFS] Concurrent ...
360
  {
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
361
362
363
364
  	struct xfs_inode	*ip = ap->ip, *pip;
  	struct xfs_mount	*mp = ip->i_mount;
  	xfs_extlen_t		minlen = ap->length;
  	xfs_agnumber_t		startag = 0;
292378edc   Dave Chinner   xfs: remote attri...
365
366
  	int			flags = 0;
  	int			err = 0;
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
367
  	struct xfs_mru_cache_elem *mru;
2a82b8be8   David Chinner   [XFS] Concurrent ...
368

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
369
  	*agp = NULLAGNUMBER;
2a82b8be8   David Chinner   [XFS] Concurrent ...
370

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
371
372
373
  	pip = xfs_filestream_get_parent(ip);
  	if (!pip)
  		goto exit;
2a82b8be8   David Chinner   [XFS] Concurrent ...
374

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
375
376
377
378
379
  	mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino);
  	if (mru) {
  		struct xfs_fstrm_item *item =
  			container_of(mru, struct xfs_fstrm_item, mru);
  		startag = (item->ag + 1) % mp->m_sb.sb_agcount;
2a82b8be8   David Chinner   [XFS] Concurrent ...
380
  	}
292378edc   Dave Chinner   xfs: remote attri...
381
382
383
384
  	if (xfs_alloc_is_userdata(ap->datatype))
  		flags |= XFS_PICK_USERDATA;
  	if (ap->dfops->dop_low)
  		flags |= XFS_PICK_LOWSPACE;
2a82b8be8   David Chinner   [XFS] Concurrent ...
385

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
386
  	err = xfs_filestream_pick_ag(pip, startag, agp, flags, minlen);
2a82b8be8   David Chinner   [XFS] Concurrent ...
387
388
  
  	/*
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
389
  	 * Only free the item here so we skip over the old AG earlier.
2a82b8be8   David Chinner   [XFS] Concurrent ...
390
  	 */
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
391
392
  	if (mru)
  		xfs_fstrm_free_func(mru);
2a82b8be8   David Chinner   [XFS] Concurrent ...
393

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
394
395
396
397
398
399
  	IRELE(pip);
  exit:
  	if (*agp == NULLAGNUMBER)
  		*agp = 0;
  	return err;
  }
2a82b8be8   David Chinner   [XFS] Concurrent ...
400

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
401
402
403
404
405
406
  void
  xfs_filestream_deassociate(
  	struct xfs_inode	*ip)
  {
  	xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino);
  }
2a82b8be8   David Chinner   [XFS] Concurrent ...
407

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
408
409
410
411
  int
  xfs_filestream_mount(
  	xfs_mount_t	*mp)
  {
2a82b8be8   David Chinner   [XFS] Concurrent ...
412
  	/*
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
413
414
415
416
417
  	 * The filestream timer tunable is currently fixed within the range of
  	 * one second to four minutes, with five seconds being the default.  The
  	 * group count is somewhat arbitrary, but it'd be nice to adhere to the
  	 * timer tunable to within about 10 percent.  This requires at least 10
  	 * groups.
2a82b8be8   David Chinner   [XFS] Concurrent ...
418
  	 */
2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
419
420
421
  	return xfs_mru_cache_create(&mp->m_filestream, xfs_fstrm_centisecs * 10,
  				    10, xfs_fstrm_free_func);
  }
2a82b8be8   David Chinner   [XFS] Concurrent ...
422

2cd2ef6a3   Christoph Hellwig   xfs: rewrite the ...
423
424
425
426
427
428
  void
  xfs_filestream_unmount(
  	xfs_mount_t	*mp)
  {
  	xfs_mru_cache_destroy(mp->m_filestream);
  }