linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22  5:39 [rfc][patch] mm, fs: warn on missing address space operations Nick Piggin
@ 2010-03-22  4:56 ` Andrew Morton
  2010-03-22  8:00   ` Pekka Enberg
  2010-03-22 10:40   ` Nick Piggin
  2010-03-22  9:17 ` Boaz Harrosh
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 13+ messages in thread
From: Andrew Morton @ 2010-03-22  4:56 UTC (permalink / raw)
  To: Nick Piggin; +Cc: linux-fsdevel, linux-mm, linux-kernel

On Mon, 22 Mar 2010 16:39:37 +1100 Nick Piggin <npiggin@suse.de> wrote:

> It's ugly and lazy that we do these default aops in case it has not
> been filled in by the filesystem.
> 
> A NULL operation should always mean either: we don't support the
> operation; we don't require any action; or a bug in the filesystem,
> depending on the context.
> 
> In practice, if we get rid of these fallbacks, it will be clearer
> what operations are used by a given address_space_operations struct,
> reduce branches, reduce #if BLOCK ifdefs, and should allow us to get
> rid of all the buffer_head knowledge from core mm and fs code.

I guess this is one way of waking people up.

What happens is that hundreds of bug reports land in my inbox and I get
to route them to various maintainers, most of whom don't exist, so
warnings keep on landing in my inbox.  Please send a mailing address for
my invoices.

It would be more practical, more successful and quicker to hunt down
the miscreants and send them rude emails.  Plus it would save you
money.

> We could add a patch like this which spits out a recipe for how to fix
> up filesystems and get them all converted quite easily.
> 
> ...
>
> @@ -40,8 +40,14 @@ void do_invalidatepage(struct page *page
>  	void (*invalidatepage)(struct page *, unsigned long);
>  	invalidatepage = page->mapping->a_ops->invalidatepage;
>  #ifdef CONFIG_BLOCK
> -	if (!invalidatepage)
> +	if (!invalidatepage) {
> +		static bool warned = false;
> +		if (!warned) {
> +			warned = true;
> +			print_symbol("address_space_operations %s missing invalidatepage method. Use block_invalidatepage.\n", (unsigned long)page->mapping->a_ops);
> +		}
>  		invalidatepage = block_invalidatepage;
> +	}

erk, I realise 80 cols can be a pain, but 165 cols is just out of
bounds.  Why not

	/* this fs should use block_invalidatepage() */
	WARN_ON_ONCE(!invalidatepage);


--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [rfc][patch] mm, fs: warn on missing address space operations
@ 2010-03-22  5:39 Nick Piggin
  2010-03-22  4:56 ` Andrew Morton
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Nick Piggin @ 2010-03-22  5:39 UTC (permalink / raw)
  To: linux-fsdevel, linux-mm, linux-kernel

It's ugly and lazy that we do these default aops in case it has not
been filled in by the filesystem.

A NULL operation should always mean either: we don't support the
operation; we don't require any action; or a bug in the filesystem,
depending on the context.

In practice, if we get rid of these fallbacks, it will be clearer
what operations are used by a given address_space_operations struct,
reduce branches, reduce #if BLOCK ifdefs, and should allow us to get
rid of all the buffer_head knowledge from core mm and fs code.

We could add a patch like this which spits out a recipe for how to fix
up filesystems and get them all converted quite easily.

Index: linux-2.6/mm/filemap.c
===================================================================
--- linux-2.6.orig/mm/filemap.c
+++ linux-2.6/mm/filemap.c
@@ -2472,7 +2472,14 @@ int try_to_release_page(struct page *pag
 
 	if (mapping && mapping->a_ops->releasepage)
 		return mapping->a_ops->releasepage(page, gfp_mask);
-	return try_to_free_buffers(page);
+	else {
+		static bool warned = false;
+		if (!warned) {
+			warned = true;
+			print_symbol("address_space_operations %s missing releasepage method. Use try_to_free_buffers.\n", (unsigned long)page->mapping->a_ops);
+		}
+		return try_to_free_buffers(page);
+	}
 }
 
 EXPORT_SYMBOL(try_to_release_page);
Index: linux-2.6/mm/page-writeback.c
===================================================================
--- linux-2.6.orig/mm/page-writeback.c
+++ linux-2.6/mm/page-writeback.c
@@ -1159,8 +1159,14 @@ int set_page_dirty(struct page *page)
 	if (likely(mapping)) {
 		int (*spd)(struct page *) = mapping->a_ops->set_page_dirty;
 #ifdef CONFIG_BLOCK
-		if (!spd)
+		if (!spd) {
+			static bool warned = false;
+			if (!warned) {
+				warned = true;
+				print_symbol("address_space_operations %s missing set_page_dirty method. Use __set_page_dirty_buffers.\n", (unsigned long)page->mapping->a_ops);
+			}
 			spd = __set_page_dirty_buffers;
+		}
 #endif
 		return (*spd)(page);
 	}
Index: linux-2.6/mm/truncate.c
===================================================================
--- linux-2.6.orig/mm/truncate.c
+++ linux-2.6/mm/truncate.c
@@ -16,8 +16,8 @@
 #include <linux/highmem.h>
 #include <linux/pagevec.h>
 #include <linux/task_io_accounting_ops.h>
-#include <linux/buffer_head.h>	/* grr. try_to_release_page,
-				   do_invalidatepage */
+#include <linux/buffer_head.h>	/* block_invalidatepage */
+#include <linux/kallsyms.h>
 #include "internal.h"
 
 
@@ -40,8 +40,14 @@ void do_invalidatepage(struct page *page
 	void (*invalidatepage)(struct page *, unsigned long);
 	invalidatepage = page->mapping->a_ops->invalidatepage;
 #ifdef CONFIG_BLOCK
-	if (!invalidatepage)
+	if (!invalidatepage) {
+		static bool warned = false;
+		if (!warned) {
+			warned = true;
+			print_symbol("address_space_operations %s missing invalidatepage method. Use block_invalidatepage.\n", (unsigned long)page->mapping->a_ops);
+		}
 		invalidatepage = block_invalidatepage;
+	}
 #endif
 	if (invalidatepage)
 		(*invalidatepage)(page, offset);
Index: linux-2.6/fs/inode.c
===================================================================
--- linux-2.6.orig/fs/inode.c
+++ linux-2.6/fs/inode.c
@@ -25,6 +25,7 @@
 #include <linux/mount.h>
 #include <linux/async.h>
 #include <linux/posix_acl.h>
+#include <linux/kallsyms.h>
 
 /*
  * This is needed for the following functions:
@@ -311,8 +312,14 @@ void clear_inode(struct inode *inode)
 
 	might_sleep();
 	/* XXX: filesystems should invalidate this before calling */
-	if (!mapping->a_ops->release)
+	if (!mapping->a_ops->release) {
+		static bool warned = false;
+		if (!warned) {
+			warned = true;
+			print_symbol("address_space_operations %s missing release method. Use invalidate_inode_buffers.\n", (unsigned long)mapping->a_ops);
+		}
 		invalidate_inode_buffers(inode);
+	}
 
 	BUG_ON(mapping_has_private(mapping));
 	BUG_ON(mapping->nrpages);
@@ -393,9 +400,14 @@ static int invalidate_list(struct list_h
 		if (inode->i_state & I_NEW)
 			continue;
 		mapping = &inode->i_data;
-		if (!mapping->a_ops->release)
+		if (!mapping->a_ops->release) {
+			static bool warned = false;
+			if (!warned) {
+				warned = true;
+				print_symbol("address_space_operations %s missing release method. Using invalidate_inode_buffers.\n", (unsigned long)mapping->a_ops);
+			}
 			invalidate_inode_buffers(inode);
-		else
+		} else
 			mapping->a_ops->release(mapping, AOP_RELEASE_FORCE);
 		BUG_ON(mapping_has_private(mapping));
 		if (!atomic_read(&inode->i_count)) {
@@ -497,8 +509,14 @@ static void prune_icache(int nr_to_scan)
 			spin_unlock(&inode_lock);
 			if (mapping->a_ops->release)
 				ret = mapping->a_ops->release(mapping, 0);
-			else
+			else {
+				static bool warned = false;
+				if (!warned) {
+					warned = true;
+					print_symbol("address_space_operations %s missing release method. Using remove_inode_buffers.\n", (unsigned long)mapping->a_ops);
+				}
 				ret = !remove_inode_buffers(inode);
+			}
 			if (ret)
 				reap += invalidate_mapping_pages(&inode->i_data,
 								0, -1);
Index: linux-2.6/fs/libfs.c
===================================================================
--- linux-2.6.orig/fs/libfs.c
+++ linux-2.6/fs/libfs.c
@@ -11,6 +11,7 @@
 #include <linux/exportfs.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
+#include <linux/kallsyms.h>
 
 #include <asm/uaccess.h>
 
@@ -827,9 +828,14 @@ int simple_fsync(struct file *file, stru
 	int err;
 	int ret;
 
-	if (!mapping->a_ops->sync)
+	if (!mapping->a_ops->sync) {
+		static bool warned = false;
+		if (!warned) {
+			warned = true;
+			print_symbol("address_space_operations %s missing sync method. Using sync_mapping_buffers.\n", (unsigned long)mapping->a_ops);
+		}
 		ret = sync_mapping_buffers(mapping);
-	else
+	} else
 		ret = mapping->a_ops->sync(mapping, AOP_SYNC_WRITE|AOP_SYNC_WAIT);
 
 	if (!(inode->i_state & I_DIRTY))

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22  4:56 ` Andrew Morton
@ 2010-03-22  8:00   ` Pekka Enberg
  2010-03-22 10:40   ` Nick Piggin
  1 sibling, 0 replies; 13+ messages in thread
From: Pekka Enberg @ 2010-03-22  8:00 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Nick Piggin, linux-fsdevel, linux-mm, linux-kernel

On Mon, Mar 22, 2010 at 6:56 AM, Andrew Morton
<akpm@linux-foundation.org> wrote:
> On Mon, 22 Mar 2010 16:39:37 +1100 Nick Piggin <npiggin@suse.de> wrote:
>
>> It's ugly and lazy that we do these default aops in case it has not
>> been filled in by the filesystem.
>>
>> A NULL operation should always mean either: we don't support the
>> operation; we don't require any action; or a bug in the filesystem,
>> depending on the context.
>>
>> In practice, if we get rid of these fallbacks, it will be clearer
>> what operations are used by a given address_space_operations struct,
>> reduce branches, reduce #if BLOCK ifdefs, and should allow us to get
>> rid of all the buffer_head knowledge from core mm and fs code.
>
> I guess this is one way of waking people up.
>
> What happens is that hundreds of bug reports land in my inbox and I get
> to route them to various maintainers, most of whom don't exist, so
> warnings keep on landing in my inbox.  Please send a mailing address for
> my invoices.
>
> It would be more practical, more successful and quicker to hunt down
> the miscreants and send them rude emails.  Plus it would save you
> money.
>
>> We could add a patch like this which spits out a recipe for how to fix
>> up filesystems and get them all converted quite easily.
>>
>> ...
>>
>> @@ -40,8 +40,14 @@ void do_invalidatepage(struct page *page
>>       void (*invalidatepage)(struct page *, unsigned long);
>>       invalidatepage = page->mapping->a_ops->invalidatepage;
>>  #ifdef CONFIG_BLOCK
>> -     if (!invalidatepage)
>> +     if (!invalidatepage) {
>> +             static bool warned = false;
>> +             if (!warned) {
>> +                     warned = true;
>> +                     print_symbol("address_space_operations %s missing invalidatepage method. Use block_invalidatepage.\n", (unsigned long)page->mapping->a_ops);
>> +             }
>>               invalidatepage = block_invalidatepage;
>> +     }
>
> erk, I realise 80 cols can be a pain, but 165 cols is just out of
> bounds.  Why not
>
>        /* this fs should use block_invalidatepage() */
>        WARN_ON_ONCE(!invalidatepage);

/me gets his paint bucket...

How about

    WARN_ONCE(!invalidatepage, "this fs should use block_invalidatepage()")

                           Pekka

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22  5:39 [rfc][patch] mm, fs: warn on missing address space operations Nick Piggin
  2010-03-22  4:56 ` Andrew Morton
@ 2010-03-22  9:17 ` Boaz Harrosh
  2010-03-22 10:54   ` Nick Piggin
  2010-03-22 11:07 ` Christoph Hellwig
  2010-03-22 11:55 ` Al Viro
  3 siblings, 1 reply; 13+ messages in thread
From: Boaz Harrosh @ 2010-03-22  9:17 UTC (permalink / raw)
  To: Nick Piggin; +Cc: linux-fsdevel, linux-mm, linux-kernel

On 03/22/2010 07:39 AM, Nick Piggin wrote:
> It's ugly and lazy that we do these default aops in case it has not
> been filled in by the filesystem.
> 
> A NULL operation should always mean either: we don't support the
> operation; we don't require any action; or a bug in the filesystem,
> depending on the context.
> 
> In practice, if we get rid of these fallbacks, it will be clearer
> what operations are used by a given address_space_operations struct,
> reduce branches, reduce #if BLOCK ifdefs, and should allow us to get
> rid of all the buffer_head knowledge from core mm and fs code.
> 
> We could add a patch like this which spits out a recipe for how to fix
> up filesystems and get them all converted quite easily.
> 

Guilty as charged. It could be nice if the first thing this patch will
do is: Add a comment at struct address_space_operations that states
that all operations should be defined and perhaps what are the minimum
defaults for some of these, as below. I do try to be good, I was under
the impression that defaults are OK.

Below are changes to exofs as proposed by this mail. Please comment?
I will push such a patch to exofs later.

> Index: linux-2.6/mm/filemap.c
> ===================================================================
> --- linux-2.6.orig/mm/filemap.c
> +++ linux-2.6/mm/filemap.c
> @@ -2472,7 +2472,14 @@ int try_to_release_page(struct page *pag
>  
>  	if (mapping && mapping->a_ops->releasepage)
>  		return mapping->a_ops->releasepage(page, gfp_mask);
> -	return try_to_free_buffers(page);
> +	else {
> +		static bool warned = false;
> +		if (!warned) {
> +			warned = true;
> +			print_symbol("address_space_operations %s missing releasepage method. Use try_to_free_buffers.\n", (unsigned long)page->mapping->a_ops);
> +		}
> +		return try_to_free_buffers(page);

This is not nice! we should have an export that looks like:

int default_releasepage(struct page *page, gfp_t gfp)
{
	return try_to_free_buffers(page);
}

otherwise 3ton FSes would have to define the same thing all over again

> +	}
>  }
>  
>  EXPORT_SYMBOL(try_to_release_page);
> Index: linux-2.6/mm/page-writeback.c
> ===================================================================
> --- linux-2.6.orig/mm/page-writeback.c
> +++ linux-2.6/mm/page-writeback.c
> @@ -1159,8 +1159,14 @@ int set_page_dirty(struct page *page)
>  	if (likely(mapping)) {
>  		int (*spd)(struct page *) = mapping->a_ops->set_page_dirty;
>  #ifdef CONFIG_BLOCK
> -		if (!spd)
> +		if (!spd) {
> +			static bool warned = false;
> +			if (!warned) {
> +				warned = true;
> +				print_symbol("address_space_operations %s missing set_page_dirty method. Use __set_page_dirty_buffers.\n", (unsigned long)page->mapping->a_ops);
> +			}
>  			spd = __set_page_dirty_buffers;
> +		}

We could do better then __set_page_dirty_buffers for something lots of FSes use

>  #endif
>  		return (*spd)(page);
>  	}
> Index: linux-2.6/mm/truncate.c
> ===================================================================
> --- linux-2.6.orig/mm/truncate.c
> +++ linux-2.6/mm/truncate.c
> @@ -16,8 +16,8 @@
>  #include <linux/highmem.h>
>  #include <linux/pagevec.h>
>  #include <linux/task_io_accounting_ops.h>
> -#include <linux/buffer_head.h>	/* grr. try_to_release_page,
> -				   do_invalidatepage */
> +#include <linux/buffer_head.h>	/* block_invalidatepage */
> +#include <linux/kallsyms.h>
>  #include "internal.h"
>  
>  
> @@ -40,8 +40,14 @@ void do_invalidatepage(struct page *page
>  	void (*invalidatepage)(struct page *, unsigned long);
>  	invalidatepage = page->mapping->a_ops->invalidatepage;
>  #ifdef CONFIG_BLOCK
> -	if (!invalidatepage)
> +	if (!invalidatepage) {
> +		static bool warned = false;
> +		if (!warned) {
> +			warned = true;
> +			print_symbol("address_space_operations %s missing invalidatepage method. Use block_invalidatepage.\n", (unsigned long)page->mapping->a_ops);
> +		}
>  		invalidatepage = block_invalidatepage;
> +	}
>  #endif
>  	if (invalidatepage)
>  		(*invalidatepage)(page, offset);
> Index: linux-2.6/fs/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/inode.c
> +++ linux-2.6/fs/inode.c
> @@ -25,6 +25,7 @@
>  #include <linux/mount.h>
>  #include <linux/async.h>
>  #include <linux/posix_acl.h>
> +#include <linux/kallsyms.h>
>  
>  /*
>   * This is needed for the following functions:
> @@ -311,8 +312,14 @@ void clear_inode(struct inode *inode)
>  
>  	might_sleep();
>  	/* XXX: filesystems should invalidate this before calling */
> -	if (!mapping->a_ops->release)
> +	if (!mapping->a_ops->release) {

Where is this code from? As of 2.6.34-rc2 I don't have a release in a_ops->

> +		static bool warned = false;
> +		if (!warned) {
> +			warned = true;
> +			print_symbol("address_space_operations %s missing release method. Use invalidate_inode_buffers.\n", (unsigned long)mapping->a_ops);
> +		}
>  		invalidate_inode_buffers(inode);
> +	}
>  
>  	BUG_ON(mapping_has_private(mapping));
>  	BUG_ON(mapping->nrpages);
> @@ -393,9 +400,14 @@ static int invalidate_list(struct list_h
>  		if (inode->i_state & I_NEW)
>  			continue;
>  		mapping = &inode->i_data;
> -		if (!mapping->a_ops->release)
> +		if (!mapping->a_ops->release) {

And here

> +			static bool warned = false;
> +			if (!warned) {
> +				warned = true;
> +				print_symbol("address_space_operations %s missing release method. Using invalidate_inode_buffers.\n", (unsigned long)mapping->a_ops);
> +			}
>  			invalidate_inode_buffers(inode);
> -		else
> +		} else
>  			mapping->a_ops->release(mapping, AOP_RELEASE_FORCE);
>  		BUG_ON(mapping_has_private(mapping));
>  		if (!atomic_read(&inode->i_count)) {
> @@ -497,8 +509,14 @@ static void prune_icache(int nr_to_scan)
>  			spin_unlock(&inode_lock);
>  			if (mapping->a_ops->release)
>  				ret = mapping->a_ops->release(mapping, 0);
> -			else
> +			else {
> +				static bool warned = false;
> +				if (!warned) {
> +					warned = true;
> +					print_symbol("address_space_operations %s missing release method. Using remove_inode_buffers.\n", (unsigned long)mapping->a_ops);
> +				}
>  				ret = !remove_inode_buffers(inode);
> +			}
>  			if (ret)
>  				reap += invalidate_mapping_pages(&inode->i_data,
>  								0, -1);
> Index: linux-2.6/fs/libfs.c
> ===================================================================
> --- linux-2.6.orig/fs/libfs.c
> +++ linux-2.6/fs/libfs.c
> @@ -11,6 +11,7 @@
>  #include <linux/exportfs.h>
>  #include <linux/writeback.h>
>  #include <linux/buffer_head.h>
> +#include <linux/kallsyms.h>
>  
>  #include <asm/uaccess.h>
>  
> @@ -827,9 +828,14 @@ int simple_fsync(struct file *file, stru
>  	int err;
>  	int ret;
>  
> -	if (!mapping->a_ops->sync)
> +	if (!mapping->a_ops->sync) {

And this one is new as well, right?

New added vectors should be added to all in-tree FSes by the submitter.
and a deprecate warning for out of tree FSes (If we care)

> +		static bool warned = false;
> +		if (!warned) {
> +			warned = true;
> +			print_symbol("address_space_operations %s missing sync method. Using sync_mapping_buffers.\n", (unsigned long)mapping->a_ops);
> +		}
>  		ret = sync_mapping_buffers(mapping);
> -	else
> +	} else
>  		ret = mapping->a_ops->sync(mapping, AOP_SYNC_WRITE|AOP_SYNC_WAIT);
>  
>  	if (!(inode->i_state & I_DIRTY))
> --
---
exofs: Add default address_space_operations

All vectors of address_space_operations should be initialized by the filesystem.
Add the missing parts.

---
git diff --stat -p -M fs/exofs/inode.c
 fs/exofs/inode.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index a17e4b7..85dd847 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -754,6 +754,11 @@ static int exofs_write_end(struct file *file, struct address_space *mapping,
 	return ret;
 }
 
+static int exofs_releasepage(struct page *page, gfp_t gfp)
+{
+	return try_to_free_buffers(page);
+}
+
 const struct address_space_operations exofs_aops = {
 	.readpage	= exofs_readpage,
 	.readpages	= exofs_readpages,
@@ -761,6 +766,9 @@ const struct address_space_operations exofs_aops = {
 	.writepages	= exofs_writepages,
 	.write_begin	= exofs_write_begin_export,
 	.write_end	= exofs_write_end,
+	.releasepage	= exofs_releasepage,
+	.set_page_dirty	= __set_page_dirty_buffers,
+	.invalidatepage = block_invalidatepage,
 };
 
 /******************************************************************************

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22  4:56 ` Andrew Morton
  2010-03-22  8:00   ` Pekka Enberg
@ 2010-03-22 10:40   ` Nick Piggin
  2010-03-22 13:30     ` Andrew Morton
  1 sibling, 1 reply; 13+ messages in thread
From: Nick Piggin @ 2010-03-22 10:40 UTC (permalink / raw)
  To: Andrew Morton, Pekka Enberg; +Cc: linux-fsdevel, linux-mm, linux-kernel

On Mon, Mar 22, 2010 at 12:56:10AM -0400, Andrew Morton wrote:
> On Mon, 22 Mar 2010 16:39:37 +1100 Nick Piggin <npiggin@suse.de> wrote:
> 
> > It's ugly and lazy that we do these default aops in case it has not
> > been filled in by the filesystem.
> > 
> > A NULL operation should always mean either: we don't support the
> > operation; we don't require any action; or a bug in the filesystem,
> > depending on the context.
> > 
> > In practice, if we get rid of these fallbacks, it will be clearer
> > what operations are used by a given address_space_operations struct,
> > reduce branches, reduce #if BLOCK ifdefs, and should allow us to get
> > rid of all the buffer_head knowledge from core mm and fs code.
> 
> I guess this is one way of waking people up.
> 
> What happens is that hundreds of bug reports land in my inbox and I get
> to route them to various maintainers, most of whom don't exist, so
> warnings keep on landing in my inbox.  Please send a mailing address for
> my invoices.

The Linux Foundation
1796 18th Street, Suite C
San Francisco, CA 94107

:)


> It would be more practical, more successful and quicker to hunt down
> the miscreants and send them rude emails.  Plus it would save you
> money.

I could do my best at the obvious (and easy to test filesystems) before
asking you to merge the warning patch. It's probably not totally trivial
to work out what aops are left NULL because they want the default
buffer-head helper, and which are left NULL because they aren't needed.
(this is one problem of having the default callback of course)


>
> > We could add a patch like this which spits out a recipe for how to fix
> > up filesystems and get them all converted quite easily.
> > 
> > ...
> >
> > @@ -40,8 +40,14 @@ void do_invalidatepage(struct page *page
> >  	void (*invalidatepage)(struct page *, unsigned long);
> >  	invalidatepage = page->mapping->a_ops->invalidatepage;
> >  #ifdef CONFIG_BLOCK
> > -	if (!invalidatepage)
> > +	if (!invalidatepage) {
> > +		static bool warned = false;
> > +		if (!warned) {
> > +			warned = true;
> > +			print_symbol("address_space_operations %s missing invalidatepage method. Use block_invalidatepage.\n", (unsigned long)page->mapping->a_ops);
> > +		}
> >  		invalidatepage = block_invalidatepage;
> > +	}
> 
> erk, I realise 80 cols can be a pain, but 165 cols is just out of
> bounds.  Why not
> 
> 	/* this fs should use block_invalidatepage() */
> 	WARN_ON_ONCE(!invalidatepage);

Problem is that it doesn't give you the aop name (and call trace
probably won't help). I'll make it all into a macro though.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22  9:17 ` Boaz Harrosh
@ 2010-03-22 10:54   ` Nick Piggin
  2010-03-22 12:05     ` Boaz Harrosh
  0 siblings, 1 reply; 13+ messages in thread
From: Nick Piggin @ 2010-03-22 10:54 UTC (permalink / raw)
  To: Boaz Harrosh; +Cc: linux-fsdevel, linux-mm, linux-kernel

On Mon, Mar 22, 2010 at 11:17:15AM +0200, Boaz Harrosh wrote:
> On 03/22/2010 07:39 AM, Nick Piggin wrote:
> > It's ugly and lazy that we do these default aops in case it has not
> > been filled in by the filesystem.
> > 
> > A NULL operation should always mean either: we don't support the
> > operation; we don't require any action; or a bug in the filesystem,
> > depending on the context.
> > 
> > In practice, if we get rid of these fallbacks, it will be clearer
> > what operations are used by a given address_space_operations struct,
> > reduce branches, reduce #if BLOCK ifdefs, and should allow us to get
> > rid of all the buffer_head knowledge from core mm and fs code.
> > 
> > We could add a patch like this which spits out a recipe for how to fix
> > up filesystems and get them all converted quite easily.
> > 
> 
> Guilty as charged.

Well, everyone's a bit guilty.


> It could be nice if the first thing this patch will
> do is: Add a comment at struct address_space_operations that states
> that all operations should be defined and perhaps what are the minimum
> defaults for some of these, as below. I do try to be good, I was under
> the impression that defaults are OK.

Defaults will usually be OK for aops that use buffer head functions for
their other operations.


> Below are changes to exofs as proposed by this mail. Please comment?
> I will push such a patch to exofs later.

OK, thanks very much for being such a proactive fs maintainer. And
for the comments.


> 
> > Index: linux-2.6/mm/filemap.c
> > ===================================================================
> > --- linux-2.6.orig/mm/filemap.c
> > +++ linux-2.6/mm/filemap.c
> > @@ -2472,7 +2472,14 @@ int try_to_release_page(struct page *pag
> >  
> >  	if (mapping && mapping->a_ops->releasepage)
> >  		return mapping->a_ops->releasepage(page, gfp_mask);
> > -	return try_to_free_buffers(page);
> > +	else {
> > +		static bool warned = false;
> > +		if (!warned) {
> > +			warned = true;
> > +			print_symbol("address_space_operations %s missing releasepage method. Use try_to_free_buffers.\n", (unsigned long)page->mapping->a_ops);
> > +		}
> > +		return try_to_free_buffers(page);
> 
> This is not nice! we should have an export that looks like:
> 
> int default_releasepage(struct page *page, gfp_t gfp)
> {
> 	return try_to_free_buffers(page);
> }
> 
> otherwise 3ton FSes would have to define the same thing all over again

Yes definitely (or block_releasepage really).

> 
> > +	}
> >  }
> >  
> >  EXPORT_SYMBOL(try_to_release_page);
> > Index: linux-2.6/mm/page-writeback.c
> > ===================================================================
> > --- linux-2.6.orig/mm/page-writeback.c
> > +++ linux-2.6/mm/page-writeback.c
> > @@ -1159,8 +1159,14 @@ int set_page_dirty(struct page *page)
> >  	if (likely(mapping)) {
> >  		int (*spd)(struct page *) = mapping->a_ops->set_page_dirty;
> >  #ifdef CONFIG_BLOCK
> > -		if (!spd)
> > +		if (!spd) {
> > +			static bool warned = false;
> > +			if (!warned) {
> > +				warned = true;
> > +				print_symbol("address_space_operations %s missing set_page_dirty method. Use __set_page_dirty_buffers.\n", (unsigned long)page->mapping->a_ops);
> > +			}
> >  			spd = __set_page_dirty_buffers;
> > +		}
> 
> We could do better then __set_page_dirty_buffers for something lots of FSes use

block_set_page_dirty? I don't know, not such a big deal and it's already
widely used. Probably worry about renames as another issue. (I do agree
that good names are important though)


> > @@ -311,8 +312,14 @@ void clear_inode(struct inode *inode)
> >  
> >  	might_sleep();
> >  	/* XXX: filesystems should invalidate this before calling */
> > -	if (!mapping->a_ops->release)
> > +	if (!mapping->a_ops->release) {
> 
> Where is this code from? As of 2.6.34-rc2 I don't have a release in a_ops->

Sorry this is from the earlier patch I posted (get rid of buffer heads
from mm/fs). That is what prompted this patch.


> > @@ -827,9 +828,14 @@ int simple_fsync(struct file *file, stru
> >  	int err;
> >  	int ret;
> >  
> > -	if (!mapping->a_ops->sync)
> > +	if (!mapping->a_ops->sync) {
> 
> And this one is new as well, right?
> 
> New added vectors should be added to all in-tree FSes by the submitter.

Yes they should. Although maybe not trivial because the fs may not
use that functionality even if it uses buffer-heads. We don't want
to fill in an operation if it is unused. But the patches should go
through fs maintainers trees.


> and a deprecate warning for out of tree FSes (If we care)

We do care, and yes this is another good reason for the warnings (even
once we do fix up all in-tree filesystems).

> 
> > +		static bool warned = false;
> > +		if (!warned) {
> > +			warned = true;
> > +			print_symbol("address_space_operations %s missing sync method. Using sync_mapping_buffers.\n", (unsigned long)mapping->a_ops);
> > +		}
> >  		ret = sync_mapping_buffers(mapping);
> > -	else
> > +	} else
> >  		ret = mapping->a_ops->sync(mapping, AOP_SYNC_WRITE|AOP_SYNC_WAIT);
> >  
> >  	if (!(inode->i_state & I_DIRTY))
> > --
> ---
> exofs: Add default address_space_operations
> 
> All vectors of address_space_operations should be initialized by the filesystem.
> Add the missing parts.
> 
> ---
> git diff --stat -p -M fs/exofs/inode.c
>  fs/exofs/inode.c |    8 ++++++++
>  1 files changed, 8 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
> index a17e4b7..85dd847 100644
> --- a/fs/exofs/inode.c
> +++ b/fs/exofs/inode.c
> @@ -754,6 +754,11 @@ static int exofs_write_end(struct file *file, struct address_space *mapping,
>  	return ret;
>  }
>  
> +static int exofs_releasepage(struct page *page, gfp_t gfp)
> +{
> +	return try_to_free_buffers(page);
> +}
> +
>  const struct address_space_operations exofs_aops = {
>  	.readpage	= exofs_readpage,
>  	.readpages	= exofs_readpages,
> @@ -761,6 +766,9 @@ const struct address_space_operations exofs_aops = {
>  	.writepages	= exofs_writepages,
>  	.write_begin	= exofs_write_begin_export,
>  	.write_end	= exofs_write_end,
> +	.releasepage	= exofs_releasepage,
> +	.set_page_dirty	= __set_page_dirty_buffers,
> +	.invalidatepage = block_invalidatepage,
>  };

AFAIKS, you aren't using buffer heads at all (except nobh_truncate,
which will not attach buffers to pages)?

If so, you should only need __set_page_dirty_nobuffers.

Thanks,
Nick


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22  5:39 [rfc][patch] mm, fs: warn on missing address space operations Nick Piggin
  2010-03-22  4:56 ` Andrew Morton
  2010-03-22  9:17 ` Boaz Harrosh
@ 2010-03-22 11:07 ` Christoph Hellwig
  2010-03-22 11:33   ` Nick Piggin
  2010-03-22 11:55 ` Al Viro
  3 siblings, 1 reply; 13+ messages in thread
From: Christoph Hellwig @ 2010-03-22 11:07 UTC (permalink / raw)
  To: Nick Piggin; +Cc: linux-fsdevel, linux-mm, linux-kernel

> @@ -2472,7 +2472,14 @@ int try_to_release_page(struct page *pag
>  
>  	if (mapping && mapping->a_ops->releasepage)
>  		return mapping->a_ops->releasepage(page, gfp_mask);
> -	return try_to_free_buffers(page);
> +	else {
> +		static bool warned = false;
> +		if (!warned) {
> +			warned = true;
> +			print_symbol("address_space_operations %s missing releasepage method. Use try_to_free_buffers.\n", (unsigned long)page->mapping->a_ops);
> +		}
> +		return try_to_free_buffers(page);
> +	}

I don't think this is correct.  We currently also call
try_to_free_buffers if the page does not have a mapping, and from
conversations with Andrew long time ago that case actually does seem to
be nessecary due to behaviour in ext3/jbd.  So you really should
only warn if there is a mapping to start with.  In fact your code will
dereference a potential NULL pointer in that case.

And as others said, this patch only makes sense after the existing
filesystems are updated to fill out all methods, and for the case
of try_to_free_buffers and set_page_dirty until we have suitable
and well-named default operations available.

Btw, any reason this doesn't use the %pf specifier to printk
instead of dragging in print_symbol?  Even better would
be to just print the fs type from mapping->host->i_sb->s_type->name.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22 11:07 ` Christoph Hellwig
@ 2010-03-22 11:33   ` Nick Piggin
  0 siblings, 0 replies; 13+ messages in thread
From: Nick Piggin @ 2010-03-22 11:33 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-fsdevel, linux-mm, linux-kernel

On Mon, Mar 22, 2010 at 07:07:58AM -0400, Christoph Hellwig wrote:
> > @@ -2472,7 +2472,14 @@ int try_to_release_page(struct page *pag
> >  
> >  	if (mapping && mapping->a_ops->releasepage)
> >  		return mapping->a_ops->releasepage(page, gfp_mask);
> > -	return try_to_free_buffers(page);
> > +	else {
> > +		static bool warned = false;
> > +		if (!warned) {
> > +			warned = true;
> > +			print_symbol("address_space_operations %s missing releasepage method. Use try_to_free_buffers.\n", (unsigned long)page->mapping->a_ops);
> > +		}
> > +		return try_to_free_buffers(page);
> > +	}
> 
> I don't think this is correct.  We currently also call
> try_to_free_buffers if the page does not have a mapping, and from
> conversations with Andrew long time ago that case actually does seem to
> be nessecary due to behaviour in ext3/jbd.  So you really should
> only warn if there is a mapping to start with.  In fact your code will
> dereference a potential NULL pointer in that case.

Good point.

I think some of that code is actually dead.

is_page_cache_freeable will check for the page reclaim reference,
the pagecache reference, and the PagePrivate reference.

If the page is removed from pagecache, that reference will be
dropped but is_page_cache_freeable() will not consider that and
fail.

NULL page can still come in there from buffer_heads_over_limit AFAIKS,
but if we are relying on that for freeing pages then it can break if a
lot of memory is tied up in other things.

That's all really ugly too. It means no other filesystem may take an 
action to take in case of NULL page->mapping, which means it is really
the wrong thing to do. Fortunately fsblock has proper refcounting so it
would never need to handle this case.

> 
> And as others said, this patch only makes sense after the existing
> filesystems are updated to fill out all methods, and for the case
> of try_to_free_buffers and set_page_dirty until we have suitable
> and well-named default operations available.

__set_page_dirty_nobuffers seems OK. Everyone has had to use that
until now anyway. Agreed about try_to_free_buffers.

> 
> Btw, any reason this doesn't use the %pf specifier to printk
> instead of dragging in print_symbol?  Even better would
> be to just print the fs type from mapping->host->i_sb->s_type->name.

Ah, because I didn't know about it. Thanks. Name I guess can be
ambiguous if there is more than one aop. I'll make it a macro and
print both maybe.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22  5:39 [rfc][patch] mm, fs: warn on missing address space operations Nick Piggin
                   ` (2 preceding siblings ...)
  2010-03-22 11:07 ` Christoph Hellwig
@ 2010-03-22 11:55 ` Al Viro
  2010-03-22 12:26   ` Nick Piggin
  3 siblings, 1 reply; 13+ messages in thread
From: Al Viro @ 2010-03-22 11:55 UTC (permalink / raw)
  To: Nick Piggin; +Cc: linux-fsdevel, linux-mm, linux-kernel

On Mon, Mar 22, 2010 at 04:39:37PM +1100, Nick Piggin wrote:
> It's ugly and lazy that we do these default aops in case it has not
> been filled in by the filesystem.
> 
> A NULL operation should always mean either: we don't support the
> operation; we don't require any action; or a bug in the filesystem,
> depending on the context.
> 
> In practice, if we get rid of these fallbacks, it will be clearer
> what operations are used by a given address_space_operations struct,
> reduce branches, reduce #if BLOCK ifdefs, and should allow us to get
> rid of all the buffer_head knowledge from core mm and fs code.
> 
> We could add a patch like this which spits out a recipe for how to fix
> up filesystems and get them all converted quite easily.

Um.  Seeing that part of that is for methods absent in mainline (->release(),
->sync()), I'd say that making it mandatory at that point is a bad idea.

As for the rest...  We have 90 instances of address_space_operations
in the kernel.  Out of those:
	28 have ->releasepage != NULL
	27 have ->set_page_dirty != NULL
	25 have ->invalidatepage != NULL

So I'm not even sure that adding that much boilerplate makes sense.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22 10:54   ` Nick Piggin
@ 2010-03-22 12:05     ` Boaz Harrosh
  0 siblings, 0 replies; 13+ messages in thread
From: Boaz Harrosh @ 2010-03-22 12:05 UTC (permalink / raw)
  To: Nick Piggin; +Cc: linux-fsdevel, linux-mm, linux-kernel

On 03/22/2010 12:54 PM, Nick Piggin wrote:
> On Mon, Mar 22, 2010 at 11:17:15AM +0200, Boaz Harrosh wrote:
>> ---
>> git diff --stat -p -M fs/exofs/inode.c
>>  fs/exofs/inode.c |    8 ++++++++
>>  1 files changed, 8 insertions(+), 0 deletions(-)
>>
>> diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
>> index a17e4b7..85dd847 100644
>> --- a/fs/exofs/inode.c
>> +++ b/fs/exofs/inode.c
>> @@ -754,6 +754,11 @@ static int exofs_write_end(struct file *file, struct address_space *mapping,
>>  	return ret;
>>  }
>>  
>> +static int exofs_releasepage(struct page *page, gfp_t gfp)
>> +{
>> +	return try_to_free_buffers(page);
>> +}
>> +
>>  const struct address_space_operations exofs_aops = {
>>  	.readpage	= exofs_readpage,
>>  	.readpages	= exofs_readpages,
>> @@ -761,6 +766,9 @@ const struct address_space_operations exofs_aops = {
>>  	.writepages	= exofs_writepages,
>>  	.write_begin	= exofs_write_begin_export,
>>  	.write_end	= exofs_write_end,
>> +	.releasepage	= exofs_releasepage,
>> +	.set_page_dirty	= __set_page_dirty_buffers,
>> +	.invalidatepage = block_invalidatepage,
>>  };
> 
> AFAIKS, you aren't using buffer heads at all (except nobh_truncate,
> which will not attach buffers to pages)?
> 
> If so, you should only need __set_page_dirty_nobuffers.
> 

Ho, thanks, that one is much better, yes.

BTW:
The use of nobh_truncate, I hope will go away after your:
	fs: truncate introduce new sequence
with these two helpers you added I can actually get rid of
that as well. (I think. I keep postponing this work ;-))

> Thanks,
> Nick
> 

Thanks
Boaz

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22 11:55 ` Al Viro
@ 2010-03-22 12:26   ` Nick Piggin
  0 siblings, 0 replies; 13+ messages in thread
From: Nick Piggin @ 2010-03-22 12:26 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel, linux-mm, linux-kernel

On Mon, Mar 22, 2010 at 11:55:08AM +0000, Al Viro wrote:
> On Mon, Mar 22, 2010 at 04:39:37PM +1100, Nick Piggin wrote:
> > It's ugly and lazy that we do these default aops in case it has not
> > been filled in by the filesystem.
> > 
> > A NULL operation should always mean either: we don't support the
> > operation; we don't require any action; or a bug in the filesystem,
> > depending on the context.
> > 
> > In practice, if we get rid of these fallbacks, it will be clearer
> > what operations are used by a given address_space_operations struct,
> > reduce branches, reduce #if BLOCK ifdefs, and should allow us to get
> > rid of all the buffer_head knowledge from core mm and fs code.
> > 
> > We could add a patch like this which spits out a recipe for how to fix
> > up filesystems and get them all converted quite easily.
> 
> Um.  Seeing that part of that is for methods absent in mainline (->release(),
> ->sync()), I'd say that making it mandatory at that point is a bad idea.

Yea I didn't have patch order right for a real submission. And clearly
_most_ of the in-tree fses should be converted before actually merging
such warnings.

> 
> As for the rest...  We have 90 instances of address_space_operations
> in the kernel.  Out of those:
> 	28 have ->releasepage != NULL
> 	27 have ->set_page_dirty != NULL
> 	25 have ->invalidatepage != NULL
> 
> So I'm not even sure that adding that much boilerplate makes sense.

Fair position. The arguments pro are more about cleaner code than any
major improvement. Main thing I don't like that it isn't trivial to see
whether an address space class will use a given function or not. You'd
have to first check the aop to find it's NULL, then check callers to see
whether there is a fallback, then check the fs in case it can attach
buffers that will still be attached at point of calls.

I personally would prefer function pointers filled in.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22 10:40   ` Nick Piggin
@ 2010-03-22 13:30     ` Andrew Morton
  2010-03-22 21:01       ` Nick Piggin
  0 siblings, 1 reply; 13+ messages in thread
From: Andrew Morton @ 2010-03-22 13:30 UTC (permalink / raw)
  To: Nick Piggin; +Cc: Pekka Enberg, linux-fsdevel, linux-mm, linux-kernel

On Mon, 22 Mar 2010 21:40:57 +1100 Nick Piggin <npiggin@suse.de> wrote:

> > 
> > 	/* this fs should use block_invalidatepage() */
> > 	WARN_ON_ONCE(!invalidatepage);
> 
> Problem is that it doesn't give you the aop name (and call trace
> probably won't help).

Yes it does - you have the filename and line number.  You go there and
read "invalidatepage".  And the backtrace identifies the filesystem.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [rfc][patch] mm, fs: warn on missing address space operations
  2010-03-22 13:30     ` Andrew Morton
@ 2010-03-22 21:01       ` Nick Piggin
  0 siblings, 0 replies; 13+ messages in thread
From: Nick Piggin @ 2010-03-22 21:01 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Pekka Enberg, linux-fsdevel, linux-mm, linux-kernel

On Mon, Mar 22, 2010 at 09:30:41AM -0400, Andrew Morton wrote:
> On Mon, 22 Mar 2010 21:40:57 +1100 Nick Piggin <npiggin@suse.de> wrote:
> 
> > > 
> > > 	/* this fs should use block_invalidatepage() */
> > > 	WARN_ON_ONCE(!invalidatepage);
> > 
> > Problem is that it doesn't give you the aop name (and call trace
> > probably won't help).
> 
> Yes it does - you have the filename and line number.  You go there and
> read "invalidatepage".  And the backtrace identifies the filesystem.

The backtrace is usually coming from just generic code paths though.
Granted that it's usually not too hard to figure what filesystem it is
(although it may have several aops).

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2010-03-22 21:01 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-22  5:39 [rfc][patch] mm, fs: warn on missing address space operations Nick Piggin
2010-03-22  4:56 ` Andrew Morton
2010-03-22  8:00   ` Pekka Enberg
2010-03-22 10:40   ` Nick Piggin
2010-03-22 13:30     ` Andrew Morton
2010-03-22 21:01       ` Nick Piggin
2010-03-22  9:17 ` Boaz Harrosh
2010-03-22 10:54   ` Nick Piggin
2010-03-22 12:05     ` Boaz Harrosh
2010-03-22 11:07 ` Christoph Hellwig
2010-03-22 11:33   ` Nick Piggin
2010-03-22 11:55 ` Al Viro
2010-03-22 12:26   ` Nick Piggin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).