xfs_filestream.c 12.5 KB
Newer Older
1 2
/*
 * Copyright (c) 2006-2007 Silicon Graphics, Inc.
3
 * Copyright (c) 2014 Christoph Hellwig.
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"
20
#include "xfs_format.h"
21 22 23 24 25
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
#include "xfs_ag.h"
#include "xfs_sb.h"
#include "xfs_mount.h"
26 27 28
#include "xfs_inum.h"
#include "xfs_inode.h"
#include "xfs_bmap.h"
D
Dave Chinner 已提交
29
#include "xfs_bmap_util.h"
30 31
#include "xfs_alloc.h"
#include "xfs_mru_cache.h"
32
#include "xfs_dinode.h"
33
#include "xfs_filestream.h"
C
Christoph Hellwig 已提交
34
#include "xfs_trace.h"
35 36 37 38 39 40 41 42 43

#define TRACE_AG_SCAN(mp, ag, ag2)
#define TRACE_AG_PICK1(mp, max_ag, maxfree)
#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag)
#define TRACE_FREE(mp, ip, pip, ag, cnt)
#define TRACE_LOOKUP(mp, ip, pip, ag, cnt)

static kmem_zone_t *item_zone;

44 45 46 47 48 49 50 51 52 53
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,
};
54

55 56
/*
 * Allocation group filestream associations are tracked with per-ag atomic
57
 * counters.  These counters allow xfs_filestream_pick_ag() to tell whether a
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 83 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 122 123 124 125 126 127 128 129 130
 * 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.
 */
static int
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);
}
131

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
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);

	TRACE_FREE(mp, ip, NULL, item->ag,
		   xfs_filestream_peek_ag(mp, item->ag));

	kmem_zone_free(item_zone, item);
}

147 148 149 150 151
/*
 * Scan the AGs starting at startag looking for an AG that isn't in use and has
 * at least minlen blocks free.
 */
static int
152 153 154 155 156 157
xfs_filestream_pick_ag(
	struct xfs_inode	*ip,
	xfs_agnumber_t		startag,
	xfs_agnumber_t		*agp,
	int			flags,
	xfs_extlen_t		minlen)
158
{
159 160 161 162 163 164 165 166 167
	struct xfs_mount	*mp = ip->i_mount;
	struct xfs_fstrm_item	*item;
	struct xfs_perag	*pag;
	xfs_extlen_t		longest, free, minfree, maxfree = 0;
	xfs_agnumber_t		ag, max_ag = NULLAGNUMBER;
	int			streams, max_streams;
	int			err, trylock, nscan;

	ASSERT(S_ISDIR(ip->i_d.di_mode));
168 169 170 171 172 173 174 175 176 177 178

	/* 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++) {
179 180
		pag = xfs_perag_get(mp, ag);
		TRACE_AG_SCAN(mp, ag, atomic_read(&pag->pagf_fstrms));
181 182 183

		if (!pag->pagf_init) {
			err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);
184 185
			if (err && !trylock) {
				xfs_perag_put(pag);
186
				return err;
187
			}
188 189 190 191 192 193 194 195 196
		}

		/* 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;
197
			max_streams = atomic_read(&pag->pagf_fstrms);
198 199 200 201 202 203 204 205 206 207 208 209 210 211
			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;
		}

212
		longest = xfs_alloc_longest_free_extent(mp, pag);
213 214 215 216 217 218 219
		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;
220 221
			streams = atomic_read(&pag->pagf_fstrms);
			xfs_perag_put(pag);
222 223 224 225 226 227 228
			*agp = ag;
			break;
		}

		/* Drop the reference on this AG, it's not usable. */
		xfs_filestream_put_ag(mp, ag);
next_ag:
229
		xfs_perag_put(pag);
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
		/* 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);
			TRACE_AG_PICK1(mp, max_ag, maxfree);
257
			streams = max_streams;
258 259 260 261 262 263 264 265 266 267 268
			free = maxfree;
			*agp = max_ag;
			break;
		}

		/* take AG 0 if none matched */
		TRACE_AG_PICK1(mp, max_ag, maxfree);
		*agp = 0;
		return 0;
	}

269
	TRACE_AG_PICK2(mp, startag, *agp, streams, free, nscan, flags);
270

271
	if (*agp == NULLAGNUMBER)
272 273
		return 0;

274
	err = ENOMEM;
275 276
	item = kmem_zone_zalloc(item_zone, KM_MAYFAIL);
	if (!item)
277
		goto out_put_ag;
278

279
	item->ag = *agp;
280 281
	item->ip = ip;

282
	err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru);
283
	if (err) {
284 285 286
		if (err == EEXIST)
			err = 0;
		goto out_free_item;
287 288 289 290
	}

	return 0;

291
out_free_item:
292
	kmem_zone_free(item_zone, item);
293 294 295
out_put_ag:
	xfs_filestream_put_ag(mp, *agp);
	return err;
296 297
}

298 299 300
static struct xfs_inode *
xfs_filestream_get_parent(
	struct xfs_inode	*ip)
301
{
302 303
	struct inode		*inode = VFS_I(ip), *dir = NULL;
	struct dentry		*dentry, *parent;
304

305 306 307
	dentry = d_find_alias(inode);
	if (!dentry)
		goto out;
308

309 310 311
	parent = dget_parent(dentry);
	if (!parent)
		goto out_dput;
312

313 314
	dir = igrab(parent->d_inode);
	dput(parent);
315

316 317 318 319
out_dput:
	dput(dentry);
out:
	return dir ? XFS_I(dir) : NULL;
320 321 322 323 324 325 326 327
}

/*
 * Return the AG of the filestream the file or directory belongs to, or
 * NULLAGNUMBER otherwise.
 */
xfs_agnumber_t
xfs_filestream_lookup_ag(
328
	struct xfs_inode	*ip)
329
{
330 331 332 333 334
	struct xfs_mount	*mp = ip->i_mount;
	struct xfs_fstrm_item	*item;
	struct xfs_inode	*pip = NULL;
	xfs_agnumber_t		ag = NULLAGNUMBER;
	int			ref = 0;
335
	struct xfs_mru_cache_elem *mru;
336

337
	ASSERT(S_ISREG(ip->i_d.di_mode));
338

339 340 341 342 343 344 345 346 347
	pip = xfs_filestream_get_parent(ip);
	if (!pip)
		goto out;

	mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
	if (!mru)
		goto out;

	item = container_of(mru, struct xfs_fstrm_item, mru);
348 349

	ag = item->ag;
350
	xfs_mru_cache_done(mp->m_filestream);
351

352 353 354 355
	ref = xfs_filestream_peek_ag(ip->i_mount, ag);
out:
	TRACE_LOOKUP(mp, ip, pip, ag, ref);
	IRELE(pip);
356 357 358 359
	return ag;
}

/*
360
 * Make sure a directory has a filestream associated with it.
361
 *
362 363 364
 * This is called when creating regular files in an directory that has
 * filestreams enabled, so that a stream is ready by the time we need it
 * in the allocator for the files inside the directory.
365 366 367
 */
int
xfs_filestream_associate(
368
	struct xfs_inode	*pip)
369
{
370
	struct xfs_mount	*mp = pip->i_mount;
371
	struct xfs_mru_cache_elem *mru;
372
	xfs_agnumber_t		startag, ag;
373

A
Al Viro 已提交
374
	ASSERT(S_ISDIR(pip->i_d.di_mode));
375 376

	/*
377
	 * If the directory already has a file stream associated we're done.
378
	 */
379 380 381
	mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
	if (mru) {
		xfs_mru_cache_done(mp->m_filestream);
382
		return 0;
383 384 385 386 387 388 389
	}

	/*
	 * Set the starting AG using the rotor for inode32, otherwise
	 * use the directory inode's AG.
	 */
	if (mp->m_flags & XFS_MOUNT_32BITINODES) {
390
		xfs_agnumber_t	 rotorstep = xfs_rotorstep;
391 392 393 394 395 396
		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);

397
	return xfs_filestream_pick_ag(pip, startag, &ag, 0, 0);
398 399 400
}

/*
401 402 403 404
 * 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.
405 406 407
 */
int
xfs_filestream_new_ag(
D
Dave Chinner 已提交
408 409
	struct xfs_bmalloca	*ap,
	xfs_agnumber_t		*agp)
410
{
411 412 413 414 415 416
	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;
	int			flags, err = 0;
	struct xfs_mru_cache_elem *mru;
417

418
	*agp = NULLAGNUMBER;
419

420 421 422
	pip = xfs_filestream_get_parent(ip);
	if (!pip)
		goto exit;
423

424 425 426 427 428
	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;
429 430 431
	}

	flags = (ap->userdata ? XFS_PICK_USERDATA : 0) |
432
	        (ap->flist->xbf_low ? XFS_PICK_LOWSPACE : 0);
433

434
	err = xfs_filestream_pick_ag(pip, startag, agp, flags, minlen);
435 436

	/*
437
	 * Only free the item here so we skip over the old AG earlier.
438
	 */
439 440
	if (mru)
		xfs_fstrm_free_func(mru);
441

442 443 444 445 446 447
	IRELE(pip);
exit:
	if (*agp == NULLAGNUMBER)
		*agp = 0;
	return err;
}
448

449 450 451 452 453 454
void
xfs_filestream_deassociate(
	struct xfs_inode	*ip)
{
	xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino);
}
455

456 457 458 459
int
xfs_filestream_mount(
	xfs_mount_t	*mp)
{
460
	/*
461 462 463 464 465
	 * 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.
466
	 */
467 468 469
	return xfs_mru_cache_create(&mp->m_filestream, xfs_fstrm_centisecs * 10,
				    10, xfs_fstrm_free_func);
}
470

471 472 473 474 475 476
void
xfs_filestream_unmount(
	xfs_mount_t	*mp)
{
	xfs_mru_cache_destroy(mp->m_filestream);
}
477

478 479 480 481 482 483 484 485 486

/* needs to return a positive errno for the init path */
int
xfs_filestream_init(void)
{
	item_zone = kmem_zone_init(sizeof(struct xfs_fstrm_item), "fstrm_item");
	if (!item_zone)
		return -ENOMEM;
	return 0;
487 488 489
}

void
490
xfs_filestream_uninit(void)
491
{
492
	kmem_zone_destroy(item_zone);
493
}