Re: [PATCH 13/22] xfs: add CRC checking to dir2 leaf blocks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Dave,

Comments below.  Basically just some nits about asserts, comments, variable
names, and looks like an off-by-one in xfs_dir3_leaf_log_header.  I would like
to know your plan for xfs_da_root_split and xfs_dir3_leaf_check_int.  

Nice find in xfs_dir2_block_to_leaf!  That should be a separate patch.

Regards,
Ben

On Wed, Apr 03, 2013 at 04:11:23PM +1100, Dave Chinner wrote:
> From: Dave Chinner <dchinner@xxxxxxxxxx>
> 
> This addition follows the same pattern as the dir2 block CRCs.
> Seeing as both LEAF1 and LEAFN types need to changed at the same
> time, this is a pretty large amount of change. leaf block headers
> neeed to be abstracted away from the on-disk structures (struct

need

> xfs_dir3_icleaf_hdr), as do the base leaf entry locations.
> 
> This header abstract allows the in-core header and leaf entry
> location to be passed around instead of the leaf block itself. This
> saves a lot of converting individual variables from on-disk format
> to host format where they are used, so there's a good chance that
> the compiler will be able to produce much more optimal code as it's
> not having to byteswap variables all over the place.
> 
> Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
> ---

...

> @@ -396,11 +397,18 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
>  		size = (int)((char *)&oldroot->btree[be16_to_cpu(oldroot->hdr.count)] -
>  			     (char *)oldroot);
>  	} else {
> -		ASSERT(oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
> +		struct xfs_dir3_icleaf_hdr leafhdr;
> +		struct xfs_dir2_leaf_entry *ents;
> +
>  		leaf = (xfs_dir2_leaf_t *)oldroot;
> -		size = (int)((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] -
> -			     (char *)leaf);
> +		xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
> +		ents = xfs_dir3_leaf_ents_p(leaf);
> +
> +		ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
> +		       leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);
> +		size = (int)((char *)&ents[leafhdr.count] - (char *)leaf);
>  	}
> +	/* XXX: can't just copy CRC headers from one block to another */

What is your plan for resolving that?

> @@ -2281,10 +2299,17 @@ xfs_da_read_buf(
>  		    XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) &&
>  				   (magic != XFS_ATTR_LEAF_MAGIC) &&
>  				   (magic != XFS_DIR2_LEAF1_MAGIC) &&
> +				   (magic != XFS_DIR3_LEAF1_MAGIC) &&
>  				   (magic != XFS_DIR2_LEAFN_MAGIC) &&
> +				   (magic != XFS_DIR3_LEAFN_MAGIC) &&
>  				   (magic1 != XFS_DIR2_BLOCK_MAGIC) &&
> +				   (magic1 != XFS_DIR3_BLOCK_MAGIC) &&

Did this DIR3_BLOCK_MAGIC change sneak in from another patch?

>  				   (magic1 != XFS_DIR2_DATA_MAGIC) &&
> -				   (free->hdr.magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)),
> +				   (magic1 != XFS_DIR3_DATA_MAGIC) &&
> +				   (free->hdr.magic !=
> +					cpu_to_be32(XFS_DIR2_FREE_MAGIC)) &&
> +				   (free->hdr.magic !=
> +					cpu_to_be32(XFS_DIR3_FREE_MAGIC)),

Do DIRx_DATA_MAGIC and DIRx_FREE_MAGIC belong in a different patch?

>  /*
>   * Get address of the bestcount field in the single-leaf block.
>   */
> +static inline struct xfs_dir2_leaf_entry *
> +xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp)
> +{
> +	if (lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
> +	    lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
> +		struct xfs_dir3_leaf *lp3 = (struct xfs_dir3_leaf *)lp;
> +		return lp3->__ents;
> +	}
> +	return lp->__ents;
> +}
> +
> +/*
> + * Get address of the bestcount field in the single-leaf block.
> + */

I appreciate the addition of the comment.

> +bool
> +xfs_dir3_leaf_check_int(
> +	struct xfs_mount	*mp,
> +	struct xfs_dir3_icleaf_hdr *hdr,
> +	struct xfs_dir2_leaf	*leaf)
> +{
> +	struct xfs_dir2_leaf_entry *ents;
> +	xfs_dir2_leaf_tail_t	*ltp;
> +	int			stale;
> +	int			i;
> +
> +	ents = xfs_dir3_leaf_ents_p(leaf);
> +	ltp = xfs_dir2_leaf_tail_p(mp, leaf);
> +
> +	/*
> +	 * This value is not restrictive enough.
> +	 * Should factor in the size of the bests table as well.
> +	 * We can deduce a value for that from di_size.
> +	 */
		^^^^^
That should probably be marked with a TODO.

> +static bool
> +xfs_dir3_leaf_verify(
>  	struct xfs_buf		*bp,
> -	__be16			magic)
> +	__uint16_t		magic)
> +{
> +	struct xfs_mount	*mp = bp->b_target->bt_mount;
> +	struct xfs_dir2_leaf	*leaf = bp->b_addr;
> +	struct xfs_dir3_icleaf_hdr leafhdr;
> +
> +	ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC);

Using v2 magics to choose between leaf1 and leafn is ok, but not as clear as
using a non-version-specific #define or enum might be for this purpose.

> @@ -169,27 +432,34 @@ xfs_dir2_block_to_leaf(
>  	/*
>  	 * Initialize the leaf block, get a buffer for it.
>  	 */
> -	if ((error = xfs_dir2_leaf_init(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC))) {
> +	error = xfs_dir3_leaf_get_buf(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC);
> +	if (error)
>  		return error;
> -	}
> -	ASSERT(lbp != NULL);
> +
>  	leaf = lbp->b_addr;
>  	hdr = dbp->b_addr;
>  	xfs_dir3_data_check(dp, dbp);
>  	btp = xfs_dir2_block_tail_p(mp, hdr);
>  	blp = xfs_dir2_block_leaf_p(btp);
>  	bf = xfs_dir3_data_bestfree_p(hdr);
> +	ents = xfs_dir3_leaf_ents_p(leaf);
> +
>  	/*
>  	 * Set the counts in the leaf header.
> +	 *
> +	 * XXX: are these actually logged, or just gathered by chance?

Nice find.  I'm not seeing where that header is being logged.  Worth a separate
patch.

>  void
> -xfs_dir2_leaf_log_header(
> +xfs_dir3_leaf_log_header(
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*bp)
>  {
> -	xfs_dir2_leaf_t		*leaf;		/* leaf structure */
> +	struct xfs_dir2_leaf	*leaf = bp->b_addr;
>  
> -	leaf = bp->b_addr;
>  	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
> -	       leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
> +	       leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
> +	       leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
> +	       leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC));
> +
>  	xfs_trans_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf),
> -		(uint)(sizeof(leaf->hdr) - 1));
> +			  xfs_dir3_leaf_hdr_size(leaf));
			  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Should be xfs_dir3_leaf_hdr_size(leaf) - 1, I think.

> @@ -1958,36 +2171,40 @@ xfs_dir2_node_to_leaf(
>  	 * Now see if the leafn and free data will fit in a leaf1.
>  	 * If not, release the buffer and give up.
>  	 */
> -	if (xfs_dir2_leaf_size(&leaf->hdr, freehdr.nvalid) > mp->m_dirblksize) {
> +	if (xfs_dir3_leaf_size(&leafhdr, freehdr.nvalid) > mp->m_dirblksize) {
>  		xfs_trans_brelse(tp, fbp);
>  		return 0;
>  	}
>  
>  	/*
>  	 * If the leaf has any stale entries in it, compress them out.
> -	 * The compact routine will log the header.
>  	 */
> -	if (be16_to_cpu(leaf->hdr.stale))
> -		xfs_dir2_leaf_compact(args, lbp);
> -	else
> -		xfs_dir2_leaf_log_header(tp, lbp);
> +	if (leafhdr.stale)
> +		xfs_dir3_leaf_compact(args, &leafhdr, lbp);
>  
> -	lbp->b_ops = &xfs_dir2_leaf1_buf_ops;
> -	leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAF1_MAGIC);
> +	lbp->b_ops = &xfs_dir3_leaf1_buf_ops;
> +	leafhdr.magic = (leafhdr.magic == XFS_DIR2_LEAFN_MAGIC)
> +					? XFS_DIR2_LEAF1_MAGIC
> +					: XFS_DIR3_LEAF1_MAGIC;

An assert might be nice here:

	if (leafhdr.magic == XFS_DIR2_LEAFN_MAGIC)
		leafhdr.magic = XFS_DIR2_LEAF1_MAGIC;
	else {
		ASSERT(leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);
		leafhdr.magic = XFS_DIR3_LEAF1_MAGIC;
	}

>  static bool
>  xfs_dir3_free_verify(
>  	struct xfs_buf		*bp)
> @@ -360,11 +385,19 @@ xfs_dir2_leaf_to_node(
>  	xfs_dir2_free_log_bests(tp, fbp, 0, freehdr.nvalid - 1);
>  	xfs_dir2_free_log_header(tp, fbp);
>  
> -	/* convert the leaf to a leafnode */
> -	leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC);
> -	lbp->b_ops = &xfs_dir2_leafn_buf_ops;
> -	xfs_dir2_leaf_log_header(tp, lbp);
> -	xfs_dir2_leafn_check(dp, lbp);
> +	/*
> +	 * Converting the leaf to a leafnode is just a matter of changing the
> +	 * magic number and the ops. Do the change directly to the buffer as
> +	 * it's less work (and less code) than decoding the header to host
> +	 * format and back again.
> +	 */
> +	if (leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC))
> +		leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC);
> +	else
> +		leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);

Here too might be a good spot for an assert in the else.

>  static void
>  xfs_dir2_free_hdr_check(
>  	struct xfs_mount *mp,
> @@ -510,15 +520,18 @@ xfs_dir2_leafn_lasthash(
>  	struct xfs_buf	*bp,			/* leaf buffer */
>  	int		*count)			/* count of entries in leaf */
>  {
> -	xfs_dir2_leaf_t	*leaf;			/* leaf structure */
> +	struct xfs_dir2_leaf	*leaf = bp->b_addr;
> +	struct xfs_dir2_leaf_entry *ents;
> +	struct xfs_dir3_icleaf_hdr leafhdr;
> +
> +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
> +	ents = xfs_dir3_leaf_ents_p(leaf);
>  
> -	leaf = bp->b_addr;
> -	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));

Looks like this assert has gone missing.  It was intentionally more specific
than the one in xfs_dir3_leaf_hdr_from_disk, right?

> @@ -547,16 +560,19 @@ xfs_dir2_leafn_lookup_for_addname(
>  	xfs_dir2_db_t		newdb;		/* new data block number */
>  	xfs_dir2_db_t		newfdb;		/* new free block number */
>  	xfs_trans_t		*tp;		/* transaction pointer */
> +	struct xfs_dir2_leaf_entry *ents;
> +	struct xfs_dir3_icleaf_hdr leafhdr;
>  
>  	dp = args->dp;
>  	tp = args->trans;
>  	mp = dp->i_mount;
>  	leaf = bp->b_addr;
> -	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));

Here the assert is also missing, but it looks like it is handled below in
xfs_dir3_leaf_check.  Maybe the above is similar.

> -#ifdef __KERNEL__
> -	ASSERT(be16_to_cpu(leaf->hdr.count) > 0);
> -#endif
> -	xfs_dir2_leafn_check(dp, bp);
> +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
> +	ents = xfs_dir3_leaf_ents_p(leaf);
> +
> +	xfs_dir3_leaf_check(mp, bp);
...

> @@ -694,16 +710,19 @@ xfs_dir2_leafn_lookup_for_entry(
>  	xfs_dir2_db_t		newdb;		/* new data block number */
>  	xfs_trans_t		*tp;		/* transaction pointer */
>  	enum xfs_dacmp		cmp;		/* comparison result */
> +	struct xfs_dir2_leaf_entry *ents;
> +	struct xfs_dir3_icleaf_hdr leafhdr;
>  
>  	dp = args->dp;
>  	tp = args->trans;
>  	mp = dp->i_mount;
>  	leaf = bp->b_addr;
> -	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));

Again.  But you've also got xfs_dir3_leaf_check below, so maybe the first one is
the only issue.

> -#ifdef __KERNEL__
> -	ASSERT(be16_to_cpu(leaf->hdr.count) > 0);
> -#endif
> -	xfs_dir2_leafn_check(dp, bp);
> +	xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
> +	ents = xfs_dir3_leaf_ents_p(leaf);
> +
> +	xfs_dir3_leaf_check(mp, bp);
...

> +xfs_dir3_leafn_moveents(
> +	xfs_da_args_t			*args,	/* operation arguments */
> +	struct xfs_buf			*bp_s,	/* source */
> +	struct xfs_dir3_icleaf_hdr	*shdr,
> +	struct xfs_dir2_leaf_entry	*sents,
> +	int				start_s,/* source leaf index */
> +	struct xfs_buf			*bp_d,	/* destination */
> +	struct xfs_dir3_icleaf_hdr	*dhdr,
> +	struct xfs_dir2_leaf_entry	*dents,
> +	int				start_d,/* destination leaf index */
> +	int				count)	/* count of leaves to copy */
>  {
> -	xfs_dir2_leaf_t	*leaf_d;		/* destination leaf structure */
> -	xfs_dir2_leaf_t	*leaf_s;		/* source leaf structure */
> -	int		stale;			/* count stale leaves copied */
> -	xfs_trans_t	*tp;			/* transaction pointer */
> +	int		stale;

I agree
						/* transaction pointer */
is a bit overkill but
						/* count stale leaves copied */
does help a new reader of this code.

> @@ -922,21 +936,25 @@ xfs_dir2_leafn_moveents(
>   */
>  int						/* sort order */
>  xfs_dir2_leafn_order(
> -	struct xfs_buf	*leaf1_bp,		/* leaf1 buffer */
> -	struct xfs_buf	*leaf2_bp)		/* leaf2 buffer */
> +	struct xfs_buf		*leaf1_bp,		/* leaf1 buffer */
> +	struct xfs_buf		*leaf2_bp)		/* leaf2 buffer */
>  {
> -	xfs_dir2_leaf_t	*leaf1;			/* leaf1 structure */
> -	xfs_dir2_leaf_t	*leaf2;			/* leaf2 structure */
> -
> -	leaf1 = leaf1_bp->b_addr;
> -	leaf2 = leaf2_bp->b_addr;
> -	ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
> -	ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));

These asserts are more specific than those in xfs_dir3_leaf_hdr_from_disk so
they should probably stay and have dirv3 magic added.

> @@ -1153,6 +1193,8 @@ xfs_dir2_leafn_remove(
>  	int			needscan;	/* need to rescan data frees */
>  	xfs_trans_t		*tp;		/* transaction pointer */
>  	struct xfs_dir2_data_free *bf;		/* bestfree table */
> +	struct xfs_dir3_icleaf_hdr leafhdr;
> +	struct xfs_dir2_leaf_entry *ents;
>  
>  	trace_xfs_dir2_leafn_remove(args, index);
>  
> @@ -1160,11 +1202,14 @@ xfs_dir2_leafn_remove(
>  	tp = args->trans;
>  	mp = dp->i_mount;
>  	leaf = bp->b_addr;
> -	ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));

Another assert that is more specific than what it is replaced with, but you do
have a leafn check, so that's something.

> @@ -1366,6 +1413,8 @@ xfs_dir2_leafn_toosmall(
>  	xfs_da_blkinfo_t	*info;		/* leaf block header */

Looks like you can get rid of the info pointer now.

> @@ -1374,10 +1423,12 @@ xfs_dir2_leafn_toosmall(
>  	 */
>  	blk = &state->path.blk[state->path.active - 1];
>  	info = blk->bp->b_addr;
> -	ASSERT(info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));

Another assert that is more specific than it's replacement.

> @@ -1428,13 +1481,15 @@ xfs_dir2_leafn_toosmall(
>  		/*
>  		 * Count bytes in the two blocks combined.
>  		 */
> -		leaf = (xfs_dir2_leaf_t *)info;
> -		count = be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);
> +		count = leafhdr.count - leafhdr.stale;
>  		bytes = state->blocksize - (state->blocksize >> 2);
> +
>  		leaf = bp->b_addr;
> -		ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
> -		count += be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);
> -		bytes -= count * (uint)sizeof(leaf->ents[0]);
				 ^^^^^ 
I wonder why that (uint) was added.

> @@ -1481,34 +1536,52 @@ xfs_dir2_leafn_unbalance(
>  	xfs_da_args_t		*args;		/* operation arguments */
>  	xfs_dir2_leaf_t		*drop_leaf;	/* dead leaf structure */
>  	xfs_dir2_leaf_t		*save_leaf;	/* surviving leaf structure */
> +	struct xfs_dir3_icleaf_hdr shdr;
> +	struct xfs_dir3_icleaf_hdr dhdr;
> +	struct xfs_dir2_leaf_entry *sents;
> +	struct xfs_dir2_leaf_entry *dents;

As I read this I really had a hard time not thinking 'source' and 'dest'
instead of 'save' and 'drop'.  This would be more readable as the latter.

>  
>  	args = state->args;
>  	ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC);
>  	ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC);
>  	drop_leaf = drop_blk->bp->b_addr;
>  	save_leaf = save_blk->bp->b_addr;
> -	ASSERT(drop_leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
> -	ASSERT(save_leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));

More specific assert than its replacement.

> +
> +	xfs_dir3_leaf_hdr_from_disk(&shdr, save_leaf);
> +	xfs_dir3_leaf_hdr_from_disk(&dhdr, drop_leaf);
> +	sents = xfs_dir3_leaf_ents_p(save_leaf);
> +	dents = xfs_dir3_leaf_ents_p(drop_leaf);
> +
>  	/*
>  	 * If there are any stale leaf entries, take this opportunity
>  	 * to purge them.
>  	 */
> -	if (drop_leaf->hdr.stale)
> -		xfs_dir2_leaf_compact(args, drop_blk->bp);
> -	if (save_leaf->hdr.stale)
> -		xfs_dir2_leaf_compact(args, save_blk->bp);
> +	if (dhdr.stale)
> +		xfs_dir3_leaf_compact(args, &dhdr, drop_blk->bp);
> +	if (shdr.stale)
> +		xfs_dir3_leaf_compact(args, &shdr, save_blk->bp);
> +
>  	/*
>  	 * Move the entries from drop to the appropriate end of save.
>  	 */
> -	drop_blk->hashval = be32_to_cpu(drop_leaf->ents[be16_to_cpu(drop_leaf->hdr.count) - 1].hashval);
> +	drop_blk->hashval = be32_to_cpu(dents[dhdr.count - 1].hashval);
>  	if (xfs_dir2_leafn_order(save_blk->bp, drop_blk->bp))
> -		xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, 0,
> -			be16_to_cpu(drop_leaf->hdr.count));
> +		xfs_dir3_leafn_moveents(args, drop_blk->bp, &dhdr, dents, 0,
> +					save_blk->bp, &shdr, sents, 0,
> +					dhdr.count);
>  	else
> -		xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp,
> -			be16_to_cpu(save_leaf->hdr.count), be16_to_cpu(drop_leaf->hdr.count));
> -	save_blk->hashval = be32_to_cpu(save_leaf->ents[be16_to_cpu(save_leaf->hdr.count) - 1].hashval);
> -	xfs_dir2_leafn_check(args->dp, save_blk->bp);
> +		xfs_dir3_leafn_moveents(args, drop_blk->bp, &dhdr, dents, 0,
> +					save_blk->bp, &shdr, sents,
> +					shdr.count, dhdr.count);
> +	save_blk->hashval = be32_to_cpu(sents[shdr.count - 1].hashval);
> +
> +	/* log the changes made when moving the entries */
> +	xfs_dir3_leaf_hdr_to_disk(save_leaf, &shdr);
> +	xfs_dir3_leaf_hdr_to_disk(drop_leaf, &dhdr);
> +	xfs_dir3_leaf_log_header(args->trans, save_blk->bp);
> +	xfs_dir3_leaf_log_header(args->trans, drop_blk->bp);
> +
> +	xfs_dir3_leaf_check(args->dp->i_mount, save_blk->bp);
	xfs_dir3_leaf_check(args->dp->i_mount, drop_block->bp);

We used to check it in debug code.  Might as well continue to do so.




_______________________________________________
xfs mailing list
xfs@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs




[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux