Re: [PATCH 1/6] sort out blockdev_direct_IO variants

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

 



On Sun 30-05-10 22:49:42, Christoph Hellwig wrote:
> Move the call to vmtruncate to get rid of accessive blocks to the callers
> in prepearation of the new truncate calling sequence.  This was only done
> for DIO_LOCKING filesystems, so the __blockdev_direct_IO_newtrunc variant
> was not needed anyway.  Get rid of blockdev_direct_IO_no_locking and
> it's _newtrunc variant while at it as just opencoding the two additional
> paramters is shorted than the name suffix.
  Hmm, I've noticed that you didn't add truncate code to btrfs. I see that
it already does some recovery after direct IO error but I'd like to make
sure that it won't be broken by your patches... Chris?

								Honza
> 
> Signed-off-by: Christoph Hellwig <hch@xxxxxx>
> 
> Index: linux-2.6/fs/block_dev.c
> ===================================================================
> --- linux-2.6.orig/fs/block_dev.c	2010-05-30 15:10:19.692004346 +0200
> +++ linux-2.6/fs/block_dev.c	2010-05-30 15:15:00.753273377 +0200
> @@ -172,9 +172,8 @@ blkdev_direct_IO(int rw, struct kiocb *i
>  	struct file *file = iocb->ki_filp;
>  	struct inode *inode = file->f_mapping->host;
>  
> -	return blockdev_direct_IO_no_locking_newtrunc(rw, iocb, inode,
> -				I_BDEV(inode), iov, offset, nr_segs,
> -				blkdev_get_blocks, NULL);
> +	return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
> +				    nr_segs, blkdev_get_blocks, NULL, NULL, 0);
>  }
>  
>  int __sync_blockdev(struct block_device *bdev, int wait)
> Index: linux-2.6/fs/direct-io.c
> ===================================================================
> --- linux-2.6.orig/fs/direct-io.c	2010-05-30 15:10:19.711004136 +0200
> +++ linux-2.6/fs/direct-io.c	2010-05-30 15:15:00.754273587 +0200
> @@ -1134,8 +1134,27 @@ direct_io_worker(int rw, struct kiocb *i
>  	return ret;
>  }
>  
> +/*
> + * This is a library function for use by filesystem drivers.
> + *
> + * The locking rules are governed by the flags parameter:
> + *  - if the flags value contains DIO_LOCKING we use a fancy locking
> + *    scheme for dumb filesystems.
> + *    For writes this function is called under i_mutex and returns with
> + *    i_mutex held, for reads, i_mutex is not held on entry, but it is
> + *    taken and dropped again before returning.
> + *    For reads and writes i_alloc_sem is taken in shared mode and released
> + *    on I/O completion (which may happen asynchronously after returning to
> + *    the caller).
> + *
> + *  - if the flags value does NOT contain DIO_LOCKING we don't use any
> + *    internal locking but rather rely on the filesystem to synchronize
> + *    direct I/O reads/writes versus each other and truncate.
> + *    For reads and writes both i_mutex and i_alloc_sem are not held on
> + *    entry and are never taken.
> + */
>  ssize_t
> -__blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
> +__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
>  	struct block_device *bdev, const struct iovec *iov, loff_t offset, 
>  	unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
>  	dio_submit_t submit_io,	int flags)
> @@ -1231,57 +1250,4 @@ __blockdev_direct_IO_newtrunc(int rw, st
>  out:
>  	return retval;
>  }
> -EXPORT_SYMBOL(__blockdev_direct_IO_newtrunc);
> -
> -/*
> - * This is a library function for use by filesystem drivers.
> - *
> - * The locking rules are governed by the flags parameter:
> - *  - if the flags value contains DIO_LOCKING we use a fancy locking
> - *    scheme for dumb filesystems.
> - *    For writes this function is called under i_mutex and returns with
> - *    i_mutex held, for reads, i_mutex is not held on entry, but it is
> - *    taken and dropped again before returning.
> - *    For reads and writes i_alloc_sem is taken in shared mode and released
> - *    on I/O completion (which may happen asynchronously after returning to
> - *    the caller).
> - *
> - *  - if the flags value does NOT contain DIO_LOCKING we don't use any
> - *    internal locking but rather rely on the filesystem to synchronize
> - *    direct I/O reads/writes versus each other and truncate.
> - *    For reads and writes both i_mutex and i_alloc_sem are not held on
> - *    entry and are never taken.
> - */
> -ssize_t
> -__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
> -	struct block_device *bdev, const struct iovec *iov, loff_t offset,
> -	unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
> -	dio_submit_t submit_io,	int flags)
> -{
> -	ssize_t retval;
> -
> -	retval = __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov,
> -			offset, nr_segs, get_block, end_io, submit_io, flags);
> -	/*
> -	 * In case of error extending write may have instantiated a few
> -	 * blocks outside i_size. Trim these off again for DIO_LOCKING.
> -	 * NOTE: DIO_NO_LOCK/DIO_OWN_LOCK callers have to handle this in
> -	 * their own manner. This is a further example of where the old
> -	 * truncate sequence is inadequate.
> -	 *
> -	 * NOTE: filesystems with their own locking have to handle this
> -	 * on their own.
> -	 */
> -	if (flags & DIO_LOCKING) {
> -		if (unlikely((rw & WRITE) && retval < 0)) {
> -			loff_t isize = i_size_read(inode);
> -			loff_t end = offset + iov_length(iov, nr_segs);
> -
> -			if (end > isize)
> -				vmtruncate(inode, isize);
> -		}
> -	}
> -
> -	return retval;
> -}
>  EXPORT_SYMBOL(__blockdev_direct_IO);
> Index: linux-2.6/fs/ext4/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/ext4/inode.c	2010-05-30 15:10:19.719003158 +0200
> +++ linux-2.6/fs/ext4/inode.c	2010-05-30 15:15:00.760003927 +0200
> @@ -3545,15 +3545,24 @@ static ssize_t ext4_ind_direct_IO(int rw
>  
>  retry:
>  	if (rw == READ && ext4_should_dioread_nolock(inode))
> -		ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
> +		ret = __blockdev_direct_IO(rw, iocb, inode,
>  				 inode->i_sb->s_bdev, iov,
>  				 offset, nr_segs,
> -				 ext4_get_block, NULL);
> -	else
> +				 ext4_get_block, NULL, NULL, 0);
> +	else {
>  		ret = blockdev_direct_IO(rw, iocb, inode,
>  				 inode->i_sb->s_bdev, iov,
>  				 offset, nr_segs,
>  				 ext4_get_block, NULL);
> +
> +		if (unlikely((rw & WRITE) && ret < 0)) {
> +			loff_t isize = i_size_read(inode);
> +			loff_t end = offset + iov_length(iov, nr_segs);
> +
> +			if (end > isize)
> +				vmtruncate(inode, isize);
> +		}
> +	}
>  	if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
>  		goto retry;
>  
> Index: linux-2.6/fs/gfs2/aops.c
> ===================================================================
> --- linux-2.6.orig/fs/gfs2/aops.c	2010-05-30 15:10:19.727004485 +0200
> +++ linux-2.6/fs/gfs2/aops.c	2010-05-30 15:15:00.768051419 +0200
> @@ -1047,9 +1047,9 @@ static ssize_t gfs2_direct_IO(int rw, st
>  	if (rv != 1)
>  		goto out; /* dio not valid, fall back to buffered i/o */
>  
> -	rv = blockdev_direct_IO_no_locking(rw, iocb, inode, inode->i_sb->s_bdev,
> -					   iov, offset, nr_segs,
> -					   gfs2_get_block_direct, NULL);
> +	rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
> +				  offset, nr_segs, gfs2_get_block_direct,
> +				  NULL, NULL, 0);
>  out:
>  	gfs2_glock_dq_m(1, &gh);
>  	gfs2_holder_uninit(&gh);
> Index: linux-2.6/fs/ocfs2/aops.c
> ===================================================================
> --- linux-2.6.orig/fs/ocfs2/aops.c	2010-05-30 15:10:19.741004625 +0200
> +++ linux-2.6/fs/ocfs2/aops.c	2010-05-30 15:15:00.776005603 +0200
> @@ -669,11 +669,10 @@ static ssize_t ocfs2_direct_IO(int rw,
>  	if (i_size_read(inode) <= offset)
>  		return 0;
>  
> -	ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
> -					    inode->i_sb->s_bdev, iov, offset,
> -					    nr_segs,
> -					    ocfs2_direct_IO_get_blocks,
> -					    ocfs2_dio_end_io);
> +	ret = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
> +				   iov, offset, nr_segs,
> +				   ocfs2_direct_IO_get_blocks,
> +				   ocfs2_dio_end_io, NULL, 0);
>  
>  	mlog_exit(ret);
>  	return ret;
> Index: linux-2.6/fs/xfs/linux-2.6/xfs_aops.c
> ===================================================================
> --- linux-2.6.orig/fs/xfs/linux-2.6/xfs_aops.c	2010-05-30 15:10:19.752024390 +0200
> +++ linux-2.6/fs/xfs/linux-2.6/xfs_aops.c	2010-05-30 15:15:00.781005533 +0200
> @@ -1658,10 +1658,9 @@ xfs_vm_direct_IO(
>  	iocb->private = xfs_alloc_ioend(inode, rw == WRITE ?
>  					IO_UNWRITTEN : IO_READ);
>  
> -	ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
> -					    offset, nr_segs,
> -					    xfs_get_blocks_direct,
> -					    xfs_end_io_direct);
> +	ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
> +				   nr_segs, xfs_get_blocks_direct,
> +				   xfs_end_io_direct, NULL, 0);
>  
>  	if (unlikely(ret != -EIOCBQUEUED && iocb->private))
>  		xfs_destroy_ioend(iocb->private);
> Index: linux-2.6/include/linux/fs.h
> ===================================================================
> --- linux-2.6.orig/include/linux/fs.h	2010-05-30 15:10:19.861004207 +0200
> +++ linux-2.6/include/linux/fs.h	2010-05-30 15:15:00.787005812 +0200
> @@ -2255,16 +2255,6 @@ static inline int xip_truncate_page(stru
>  struct bio;
>  typedef void (dio_submit_t)(int rw, struct bio *bio, struct inode *inode,
>  			    loff_t file_offset);
> -void dio_end_io(struct bio *bio, int error);
> -
> -ssize_t __blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
> -	struct block_device *bdev, const struct iovec *iov, loff_t offset,
> -	unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
> -	dio_submit_t submit_io, int lock_type);
> -ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
> -	struct block_device *bdev, const struct iovec *iov, loff_t offset,
> -	unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
> -	dio_submit_t submit_io,	int lock_type);
>  
>  enum {
>  	/* need locking between buffered and direct access */
> @@ -2274,24 +2264,13 @@ enum {
>  	DIO_SKIP_HOLES	= 0x02,
>  };
>  
> -static inline ssize_t blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb,
> -	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
> -	loff_t offset, unsigned long nr_segs, get_block_t get_block,
> -	dio_iodone_t end_io)
> -{
> -	return __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov, offset,
> -				    nr_segs, get_block, end_io, NULL,
> -				    DIO_LOCKING | DIO_SKIP_HOLES);
> -}
> +void dio_end_io(struct bio *bio, int error);
> +
> +ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
> +	struct block_device *bdev, const struct iovec *iov, loff_t offset,
> +	unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
> +	dio_submit_t submit_io,	int flags);
>  
> -static inline ssize_t blockdev_direct_IO_no_locking_newtrunc(int rw, struct kiocb *iocb,
> -	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
> -	loff_t offset, unsigned long nr_segs, get_block_t get_block,
> -	dio_iodone_t end_io)
> -{
> -	return __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov, offset,
> -				nr_segs, get_block, end_io, NULL, 0);
> -}
>  static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
>  	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
>  	loff_t offset, unsigned long nr_segs, get_block_t get_block,
> @@ -2301,15 +2280,6 @@ static inline ssize_t blockdev_direct_IO
>  				    nr_segs, get_block, end_io, NULL,
>  				    DIO_LOCKING | DIO_SKIP_HOLES);
>  }
> -
> -static inline ssize_t blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb,
> -	struct inode *inode, struct block_device *bdev, const struct iovec *iov,
> -	loff_t offset, unsigned long nr_segs, get_block_t get_block,
> -	dio_iodone_t end_io)
> -{
> -	return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
> -				    nr_segs, get_block, end_io, NULL, 0);
> -}
>  #endif
>  
>  extern const struct file_operations generic_ro_fops;
> Index: linux-2.6/fs/ext2/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/ext2/inode.c	2010-05-30 15:10:26.785274006 +0200
> +++ linux-2.6/fs/ext2/inode.c	2010-05-30 15:15:00.792005673 +0200
> @@ -831,7 +831,7 @@ ext2_direct_IO(int rw, struct kiocb *ioc
>  	struct inode *inode = mapping->host;
>  	ssize_t ret;
>  
> -	ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
> +	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
>  				iov, offset, nr_segs, ext2_get_block, NULL);
>  	if (ret < 0 && (rw & WRITE))
>  		ext2_write_failed(mapping, offset + iov_length(iov, nr_segs));
> Index: linux-2.6/fs/ext3/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/ext3/inode.c	2010-05-30 15:10:19.774004346 +0200
> +++ linux-2.6/fs/ext3/inode.c	2010-05-30 15:15:00.798005533 +0200
> @@ -1785,6 +1785,17 @@ retry:
>  	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
>  				 offset, nr_segs,
>  				 ext3_get_block, NULL);
> +	/*
> +	 * In case of error extending write may have instantiated a few
> +	 * blocks outside i_size. Trim these off again.
> +	 */
> +	if (unlikely((rw & WRITE) && ret < 0)) {
> +		loff_t isize = i_size_read(inode);
> +		loff_t end = offset + iov_length(iov, nr_segs);
> +
> +		if (end > isize)
> +			vmtruncate(inode, isize);
> +	}
>  	if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
>  		goto retry;
>  
> Index: linux-2.6/fs/fat/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/fat/inode.c	2010-05-30 15:10:19.795006092 +0200
> +++ linux-2.6/fs/fat/inode.c	2010-05-30 15:15:00.806067692 +0200
> @@ -212,8 +212,8 @@ static ssize_t fat_direct_IO(int rw, str
>  	 * FAT need to use the DIO_LOCKING for avoiding the race
>  	 * condition of fat_get_block() and ->truncate().
>  	 */
> -	ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
> -				iov, offset, nr_segs, fat_get_block, NULL);
> +	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
> +				 iov, offset, nr_segs, fat_get_block, NULL);
>  	if (ret < 0 && (rw & WRITE))
>  		fat_write_failed(mapping, offset + iov_length(iov, nr_segs));
>  
> Index: linux-2.6/fs/hfs/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/hfs/inode.c	2010-05-30 15:10:19.808003788 +0200
> +++ linux-2.6/fs/hfs/inode.c	2010-05-30 15:15:00.810051978 +0200
> @@ -112,9 +112,24 @@ static ssize_t hfs_direct_IO(int rw, str
>  {
>  	struct file *file = iocb->ki_filp;
>  	struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
> +	ssize_t ret;
>  
> -	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
> +	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
>  				  offset, nr_segs, hfs_get_block, NULL);
> +
> +	/*
> +	 * In case of error extending write may have instantiated a few
> +	 * blocks outside i_size. Trim these off again.
> +	 */
> +	if (unlikely((rw & WRITE) && ret < 0)) {
> +		loff_t isize = i_size_read(inode);
> +		loff_t end = offset + iov_length(iov, nr_segs);
> +
> +		if (end > isize)
> +			vmtruncate(inode, isize);
> +	}
> +
> +	return ret;
>  }
>  
>  static int hfs_writepages(struct address_space *mapping,
> Index: linux-2.6/fs/hfsplus/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/hfsplus/inode.c	2010-05-30 15:10:19.816011470 +0200
> +++ linux-2.6/fs/hfsplus/inode.c	2010-05-30 15:15:00.817051489 +0200
> @@ -105,9 +105,24 @@ static ssize_t hfsplus_direct_IO(int rw,
>  {
>  	struct file *file = iocb->ki_filp;
>  	struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
> +	ssize_t ret;
>  
> -	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
> +	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
>  				  offset, nr_segs, hfsplus_get_block, NULL);
> +
> +	/*
> +	 * In case of error extending write may have instantiated a few
> +	 * blocks outside i_size. Trim these off again.
> +	 */
> +	if (unlikely((rw & WRITE) && ret < 0)) {
> +		loff_t isize = i_size_read(inode);
> +		loff_t end = offset + iov_length(iov, nr_segs);
> +
> +		if (end > isize)
> +			vmtruncate(inode, isize);
> +	}
> +
> +	return ret;
>  }
>  
>  static int hfsplus_writepages(struct address_space *mapping,
> Index: linux-2.6/fs/jfs/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/jfs/inode.c	2010-05-30 15:10:19.826004346 +0200
> +++ linux-2.6/fs/jfs/inode.c	2010-05-30 15:15:00.824005463 +0200
> @@ -317,9 +317,24 @@ static ssize_t jfs_direct_IO(int rw, str
>  {
>  	struct file *file = iocb->ki_filp;
>  	struct inode *inode = file->f_mapping->host;
> +	ssize_t ret;
>  
> -	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
> +	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
>  				offset, nr_segs, jfs_get_block, NULL);
> +
> +	/*
> +	 * In case of error extending write may have instantiated a few
> +	 * blocks outside i_size. Trim these off again.
> +	 */
> +	if (unlikely((rw & WRITE) && ret < 0)) {
> +		loff_t isize = i_size_read(inode);
> +		loff_t end = offset + iov_length(iov, nr_segs);
> +
> +		if (end > isize)
> +			vmtruncate(inode, isize);
> +	}
> +
> +	return ret;
>  }
>  
>  const struct address_space_operations jfs_aops = {
> Index: linux-2.6/fs/nilfs2/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/nilfs2/inode.c	2010-05-30 15:10:19.837004346 +0200
> +++ linux-2.6/fs/nilfs2/inode.c	2010-05-30 15:15:00.830005533 +0200
> @@ -237,6 +237,19 @@ nilfs_direct_IO(int rw, struct kiocb *io
>  	/* Needs synchronization with the cleaner */
>  	size = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
>  				  offset, nr_segs, nilfs_get_block, NULL);
> +
> +	/*
> +	 * In case of error extending write may have instantiated a few
> +	 * blocks outside i_size. Trim these off again.
> +	 */
> +	if (unlikely((rw & WRITE) && size < 0)) {
> +		loff_t isize = i_size_read(inode);
> +		loff_t end = offset + iov_length(iov, nr_segs);
> +
> +		if (end > isize)
> +			vmtruncate(inode, isize);
> +	}
> +
>  	return size;
>  }
>  
> Index: linux-2.6/fs/reiserfs/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/reiserfs/inode.c	2010-05-30 15:10:19.848012727 +0200
> +++ linux-2.6/fs/reiserfs/inode.c	2010-05-30 15:15:00.835005812 +0200
> @@ -3059,10 +3059,25 @@ static ssize_t reiserfs_direct_IO(int rw
>  {
>  	struct file *file = iocb->ki_filp;
>  	struct inode *inode = file->f_mapping->host;
> +	ssize_t ret;
>  
> -	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
> +	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
>  				  offset, nr_segs,
>  				  reiserfs_get_blocks_direct_io, NULL);
> +
> +	/*
> +	 * In case of error extending write may have instantiated a few
> +	 * blocks outside i_size. Trim these off again.
> +	 */
> +	if (unlikely((rw & WRITE) && ret < 0)) {
> +		loff_t isize = i_size_read(inode);
> +		loff_t end = offset + iov_length(iov, nr_segs);
> +
> +		if (end > isize)
> +			vmtruncate(inode, isize);
> +	}
> +
> +	return ret;
>  }
>  
>  int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
-- 
Jan Kara <jack@xxxxxxx>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux