diff --git a/NEWS b/NEWS
index f0f4d8bcdd..019c2cc650 100644
--- a/NEWS
+++ b/NEWS
@@ -110,16 +110,16 @@ Deprecated and removed features, and other changes affecting compatibility:
 
 * The tilepro-*-linux-gnu configuration is no longer supported.
 
-* The nonstandard header files <libio.h> and <_G_config.h> are deprecated
-  and will be removed in a future release.  Software that is still using
-  either header should be updated to use standard <stdio.h> interfaces
-  instead.
+* The nonstandard header files <libio.h> and <_G_config.h> are deprecated.
+  <stdio.h> no longer includes either of them, and they will be removed in a
+  future release.  Software that is still using these headers, or their
+  contents, should be updated to use standard <stdio.h> interfaces instead.
 
   libio.h was originally the header for a set of supported GNU extensions,
   but they have not been maintained as such in many years, they are now
-  standing in the way of improvements to stdio, and we don't think there are
-  any remaining external users.  _G_config.h was never intended for public
-  use, but predates the bits convention.
+  standing in the way of improvements to stdio, and we are not aware of any
+  remaining external users.  _G_config.h was never intended for public use,
+  but predates the "bits" convention for private-but-installed headers.
 
 Changes to build and runtime requirements:
 
diff --git a/include/bits/types/struct_FILE.h b/include/bits/types/struct_FILE.h
new file mode 100644
index 0000000000..971407292b
--- /dev/null
+++ b/include/bits/types/struct_FILE.h
@@ -0,0 +1 @@
+#include <libio/bits/types/struct_FILE.h>
diff --git a/include/stdio_ext.h b/include/stdio_ext.h
index 29c6e68cdb..f4441def2a 100644
--- a/include/stdio_ext.h
+++ b/include/stdio_ext.h
@@ -2,6 +2,7 @@
 #include <stdio-common/stdio_ext.h>
 
 # ifndef _ISOMAC
+#  include <bits/types/struct_FILE.h>
 
 libc_hidden_proto (__fsetlocking)
 
diff --git a/libio/Makefile b/libio/Makefile
index 0e51833f62..309fa501d2 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -25,8 +25,9 @@ include ../Makeconfig
 headers	:= stdio.h libio.h _G_config.h \
 	   bits/stdio.h bits/libio.h bits/_G_config.h \
 	   bits/sys_errlist.h bits/stdio2.h bits/stdio-ldbl.h bits/libio-ldbl.h \
-	   bits/types/FILE.h bits/types/__FILE.h bits/types/__fpos_t.h \
-	   bits/types/__fpos64_t.h bits/types/cookie_io_functions_t.h
+	   bits/types/FILE.h bits/types/__FILE.h bits/types/struct_FILE.h \
+	   bits/types/__fpos_t.h bits/types/__fpos64_t.h \
+	   bits/types/cookie_io_functions_t.h
 
 routines	:=							      \
 	filedoalloc iofclose iofdopen iofflush iofgetpos iofgets iofopen      \
diff --git a/libio/bits/libio.h b/libio/bits/libio.h
index 08fa672b2a..feca5a0c87 100644
--- a/libio/bits/libio.h
+++ b/libio/bits/libio.h
@@ -28,11 +28,12 @@
 #ifndef _BITS_LIBIO_H
 #define _BITS_LIBIO_H 1
 
-#if !defined _STDIO_H && !defined _LIBIO_H && !defined _LIBIOP_H
-# error "Never include <bits/libio.h> directly; use <stdio.h> instead."
+#if !defined _LIBIO_H && !defined _LIBIOP_H
+# error "Never include <bits/libio.h> directly; use <libio.h> instead."
 #endif
 
 #include <stdio.h>
+#include <bits/types/struct_FILE.h>
 
 #include <bits/_G_config.h>
 /* ALL of these should be defined in _G_config.h */
@@ -50,9 +51,13 @@
 #define _IO_wint_t wint_t
 #define _IO_va_list __gnuc_va_list
 
+/* compatibility defines */
 #define _STDIO_USES_IOSTREAM
 #define _IO_UNIFIED_JUMPTABLES 1
+#define __HAVE_COLUMN
+#define _IO_file_flags _flags
 
+/* open modes */
 #define _IOS_INPUT	1
 #define _IOS_OUTPUT	2
 #define _IOS_ATEND	4
@@ -121,14 +126,7 @@
 #define _IO_BOOLALPHA 0200000
 
 
-struct _IO_jump_t;  struct _IO_FILE;
-
-/* During the build of glibc itself, _IO_lock_t will already have been
-   defined by internal headers.  */
-#ifndef _IO_lock_t_defined
-typedef void _IO_lock_t;
-#endif
-
+struct _IO_jump_t;
 
 /* A streammarker remembers a position in a buffer. */
 
@@ -139,16 +137,6 @@ struct _IO_marker {
  it points to _buf->Gbase()+_pos. FIXME comment */
   /* if _pos < 0, it points to _buf->eBptr()+_pos. FIXME comment */
   int _pos;
-#if 0
-    void set_streampos(streampos sp) { _spos = sp; }
-    void set_offset(int offset) { _pos = offset; _spos = (streampos)(-2); }
-  public:
-    streammarker(streambuf *sb);
-    ~streammarker();
-    int saving() { return  _spos == -2; }
-    int delta(streammarker&);
-    int delta();
-#endif
 };
 
 /* This is the structure from the libstdc++ codecvt class.  */
@@ -217,73 +205,6 @@ struct _IO_wide_data
 };
 #endif
 
-struct _IO_FILE {
-  int _flags;		/* High-order word is _IO_MAGIC; rest is flags. */
-#define _IO_file_flags _flags
-
-  /* The following pointers correspond to the C++ streambuf protocol. */
-  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
-  char* _IO_read_ptr;	/* Current read pointer */
-  char* _IO_read_end;	/* End of get area. */
-  char* _IO_read_base;	/* Start of putback+get area. */
-  char* _IO_write_base;	/* Start of put area. */
-  char* _IO_write_ptr;	/* Current put pointer. */
-  char* _IO_write_end;	/* End of put area. */
-  char* _IO_buf_base;	/* Start of reserve area. */
-  char* _IO_buf_end;	/* End of reserve area. */
-  /* The following fields are used to support backing up and undo. */
-  char *_IO_save_base; /* Pointer to start of non-current get area. */
-  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
-  char *_IO_save_end; /* Pointer to end of non-current get area. */
-
-  struct _IO_marker *_markers;
-
-  struct _IO_FILE *_chain;
-
-  int _fileno;
-#if 0
-  int _blksize;
-#else
-  int _flags2;
-#endif
-  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */
-
-#define __HAVE_COLUMN /* temporary */
-  /* 1+column number of pbase(); 0 is unknown. */
-  unsigned short _cur_column;
-  signed char _vtable_offset;
-  char _shortbuf[1];
-
-  /*  char* _save_gptr;  char* _save_egptr; */
-
-  _IO_lock_t *_lock;
-#ifdef _IO_USE_OLD_IO_FILE
-};
-
-struct _IO_FILE_complete
-{
-  struct _IO_FILE _file;
-#endif
-#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001
-  _IO_off64_t _offset;
-# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
-  /* Wide character stream stuff.  */
-  struct _IO_codecvt *_codecvt;
-  struct _IO_wide_data *_wide_data;
-  struct _IO_FILE *_freeres_list;
-  void *_freeres_buf;
-# else
-  void *__pad1;
-  void *__pad2;
-  void *__pad3;
-  void *__pad4;
-# endif
-  size_t __pad5;
-  int _mode;
-  /* Make sure we don't get into trouble again.  */
-  char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
-#endif
-};
 
 #ifndef __cplusplus
 typedef struct _IO_FILE _IO_FILE;
@@ -325,9 +246,6 @@ extern void _IO_cookie_init (struct _IO_cookie_file *__cfile, int __read_write,
 extern "C" {
 #endif
 
-extern int __underflow (_IO_FILE *);
-extern int __uflow (_IO_FILE *);
-extern int __overflow (_IO_FILE *, int);
 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
 extern _IO_wint_t __wunderflow (_IO_FILE *);
 extern _IO_wint_t __wuflow (_IO_FILE *);
@@ -340,17 +258,12 @@ extern _IO_wint_t __woverflow (_IO_FILE *, _IO_wint_t);
 # define _IO_BE(expr, res) (expr)
 #endif
 
-#define _IO_getc_unlocked(_fp) \
-       (_IO_BE ((_fp)->_IO_read_ptr >= (_fp)->_IO_read_end, 0) \
-	? __uflow (_fp) : *(unsigned char *) (_fp)->_IO_read_ptr++)
+#define _IO_getc_unlocked(_fp) __getc_unlocked_body (_fp)
 #define _IO_peekc_unlocked(_fp) \
        (_IO_BE ((_fp)->_IO_read_ptr >= (_fp)->_IO_read_end, 0) \
 	  && __underflow (_fp) == EOF ? EOF \
 	: *(unsigned char *) (_fp)->_IO_read_ptr)
-#define _IO_putc_unlocked(_ch, _fp) \
-   (_IO_BE ((_fp)->_IO_write_ptr >= (_fp)->_IO_write_end, 0) \
-    ? __overflow (_fp, (unsigned char) (_ch)) \
-    : (unsigned char) (*(_fp)->_IO_write_ptr++ = (_ch)))
+#define _IO_putc_unlocked(_ch, _fp) __putc_unlocked_body (_ch, _fp)
 
 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
 # define _IO_getwc_unlocked(_fp) \
@@ -366,8 +279,8 @@ extern _IO_wint_t __woverflow (_IO_FILE *, _IO_wint_t);
    : (_IO_wint_t) (*(_fp)->_wide_data->_IO_write_ptr++ = (_wch)))
 #endif
 
-#define _IO_feof_unlocked(__fp) (((__fp)->_flags & _IO_EOF_SEEN) != 0)
-#define _IO_ferror_unlocked(__fp) (((__fp)->_flags & _IO_ERR_SEEN) != 0)
+#define _IO_feof_unlocked(_fp) __feof_unlocked_body (_fp)
+#define _IO_ferror_unlocked(_fp) __ferror_unlocked_body (_fp)
 
 extern int _IO_getc (_IO_FILE *__fp);
 extern int _IO_putc (int __c, _IO_FILE *__fp);
@@ -386,6 +299,7 @@ extern void (_IO_funlockfile) (_IO_FILE *) __THROW;
 extern int (_IO_ftrylockfile) (_IO_FILE *) __THROW;
 
 #define _IO_peekc(_fp) _IO_peekc_unlocked (_fp)
+#if !defined _LIBC && !defined _IO_MTSAFE_IO
 #define _IO_flockfile(_fp) /**/
 #define _IO_funlockfile(_fp) /**/
 #define _IO_ftrylockfile(_fp) /**/
@@ -395,6 +309,7 @@ extern int (_IO_ftrylockfile) (_IO_FILE *) __THROW;
 #ifndef _IO_cleanup_region_end
 #define _IO_cleanup_region_end(_Doit) /**/
 #endif
+#endif
 
 #define _IO_need_lock(_fp) \
   (((_fp)->_flags2 & _IO_FLAGS2_NEED_LOCK) != 0)
diff --git a/libio/bits/stdio.h b/libio/bits/stdio.h
index 1415709eb0..90b523a7be 100644
--- a/libio/bits/stdio.h
+++ b/libio/bits/stdio.h
@@ -16,10 +16,15 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#ifndef _BITS_STDIO_H
+#define _BITS_STDIO_H 1
+
 #ifndef _STDIO_H
 # error "Never include <bits/stdio.h> directly; use <stdio.h> instead."
 #endif
 
+#include <bits/types/struct_FILE.h>
+
 #ifndef __extern_inline
 # define __STDIO_INLINE inline
 #else
@@ -43,7 +48,7 @@ vprintf (const char *__restrict __fmt, __gnuc_va_list __arg)
 __STDIO_INLINE int
 getchar (void)
 {
-  return _IO_getc (stdin);
+  return getc (stdin);
 }
 
 
@@ -52,7 +57,7 @@ getchar (void)
 __STDIO_INLINE int
 fgetc_unlocked (FILE *__fp)
 {
-  return _IO_getc_unlocked (__fp);
+  return __getc_unlocked_body (__fp);
 }
 # endif /* misc */
 
@@ -62,14 +67,14 @@ fgetc_unlocked (FILE *__fp)
 __STDIO_INLINE int
 getc_unlocked (FILE *__fp)
 {
-  return _IO_getc_unlocked (__fp);
+  return __getc_unlocked_body (__fp);
 }
 
 /* This is defined in POSIX.1:1996.  */
 __STDIO_INLINE int
 getchar_unlocked (void)
 {
-  return _IO_getc_unlocked (stdin);
+  return __getc_unlocked_body (stdin);
 }
 # endif	/* POSIX */
 
@@ -78,7 +83,7 @@ getchar_unlocked (void)
 __STDIO_INLINE int
 putchar (int __c)
 {
-  return _IO_putc (__c, stdout);
+  return putc (__c, stdout);
 }
 
 
@@ -87,7 +92,7 @@ putchar (int __c)
 __STDIO_INLINE int
 fputc_unlocked (int __c, FILE *__stream)
 {
-  return _IO_putc_unlocked (__c, __stream);
+  return __putc_unlocked_body (__c, __stream);
 }
 # endif /* misc */
 
@@ -97,14 +102,14 @@ fputc_unlocked (int __c, FILE *__stream)
 __STDIO_INLINE int
 putc_unlocked (int __c, FILE *__stream)
 {
-  return _IO_putc_unlocked (__c, __stream);
+  return __putc_unlocked_body (__c, __stream);
 }
 
 /* This is defined in POSIX.1:1996.  */
 __STDIO_INLINE int
 putchar_unlocked (int __c)
 {
-  return _IO_putc_unlocked (__c, stdout);
+  return __putc_unlocked_body (__c, stdout);
 }
 # endif	/* POSIX */
 
@@ -124,14 +129,14 @@ getline (char **__lineptr, size_t *__n, FILE *__stream)
 __STDIO_INLINE int
 __NTH (feof_unlocked (FILE *__stream))
 {
-  return _IO_feof_unlocked (__stream);
+  return __feof_unlocked_body (__stream);
 }
 
 /* Faster versions when locking is not required.  */
 __STDIO_INLINE int
 __NTH (ferror_unlocked (FILE *__stream))
 {
-  return _IO_ferror_unlocked (__stream);
+  return __ferror_unlocked_body (__stream);
 }
 # endif /* misc */
 
@@ -151,7 +156,7 @@ __NTH (ferror_unlocked (FILE *__stream))
 		       for (__cnt = (size_t) (size) * (size_t) (n);	      \
 			    __cnt > 0; --__cnt)				      \
 			 {						      \
-			   int __c = _IO_getc_unlocked (__stream);	      \
+			   int __c = getc_unlocked (__stream);		      \
 			   if (__c == EOF)				      \
 			     break;					      \
 			   *__ptr++ = __c;				      \
@@ -174,7 +179,7 @@ __NTH (ferror_unlocked (FILE *__stream))
 		       size_t __cnt;					      \
 		       for (__cnt = (size_t) (size) * (size_t) (n);	      \
 			    __cnt > 0; --__cnt)				      \
-			 if (_IO_putc_unlocked (*__ptr++, __stream) == EOF)   \
+			 if (putc_unlocked (*__ptr++, __stream) == EOF)	      \
 			   break;					      \
 		       ((size_t) (size) * (size_t) (n) - __cnt)		      \
 			/ (size_t) (size); })				      \
@@ -188,3 +193,5 @@ __NTH (ferror_unlocked (FILE *__stream))
 
 /* Define helper macro.  */
 #undef __STDIO_INLINE
+
+#endif /* bits/stdio.h.  */
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
index 0ab62ef913..11651506a6 100644
--- a/libio/bits/stdio2.h
+++ b/libio/bits/stdio2.h
@@ -16,6 +16,9 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#ifndef _BITS_STDIO2_H
+#define _BITS_STDIO2_H 1
+
 #ifndef _STDIO_H
 # error "Never include <bits/stdio2.h> directly; use <stdio.h> instead."
 #endif
@@ -368,7 +371,7 @@ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
 
       for (; __cnt > 0; --__cnt)
 	{
-	  int __c = _IO_getc_unlocked (__stream);
+	  int __c = getc_unlocked (__stream);
 	  if (__c == EOF)
 	    break;
 	  *__cptr++ = __c;
@@ -379,3 +382,5 @@ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
   return __fread_unlocked_alias (__ptr, __size, __n, __stream);
 }
 #endif
+
+#endif /* bits/stdio2.h.  */
diff --git a/libio/bits/types/struct_FILE.h b/libio/bits/types/struct_FILE.h
new file mode 100644
index 0000000000..a7598886f4
--- /dev/null
+++ b/libio/bits/types/struct_FILE.h
@@ -0,0 +1,103 @@
+#ifndef __struct_FILE_defined
+#define __struct_FILE_defined 1
+
+/* Caution: The contents of this file are not part of the official
+   stdio.h API.  However, much of it is part of the official *binary*
+   interface, and therefore cannot be changed.  */
+
+#if defined _IO_USE_OLD_IO_FILE && !defined _LIBC
+# error "_IO_USE_OLD_IO_FILE should only be defined when building libc itself"
+#endif
+
+#if defined _IO_lock_t_defined && !defined _LIBC
+# error "_IO_lock_t_defined should only be defined when building libc itself"
+#endif
+
+#include <bits/types.h>
+
+struct _IO_FILE;
+struct _IO_marker;
+struct _IO_codecvt;
+struct _IO_wide_data;
+
+/* During the build of glibc itself, _IO_lock_t will already have been
+   defined by internal headers.  */
+#ifndef _IO_lock_t_defined
+typedef void _IO_lock_t;
+#endif
+
+/* Note: the tag name of this struct is _IO_FILE to preserve historic
+   C++ mangled names for functions taking FILE* arguments.  That name
+   should not be used in new code.  */
+struct _IO_FILE
+{
+  int _flags;		/* High-order word is _IO_MAGIC; rest is flags. */
+
+  /* The following pointers correspond to the C++ streambuf protocol. */
+  char *_IO_read_ptr;	/* Current read pointer */
+  char *_IO_read_end;	/* End of get area. */
+  char *_IO_read_base;	/* Start of putback+get area. */
+  char *_IO_write_base;	/* Start of put area. */
+  char *_IO_write_ptr;	/* Current put pointer. */
+  char *_IO_write_end;	/* End of put area. */
+  char *_IO_buf_base;	/* Start of reserve area. */
+  char *_IO_buf_end;	/* End of reserve area. */
+
+  /* The following fields are used to support backing up and undo. */
+  char *_IO_save_base; /* Pointer to start of non-current get area. */
+  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
+  char *_IO_save_end; /* Pointer to end of non-current get area. */
+
+  struct _IO_marker *_markers;
+
+  struct _IO_FILE *_chain;
+
+  int _fileno;
+  int _flags2;
+  __off_t _old_offset; /* This used to be _offset but it's too small.  */
+
+  /* 1+column number of pbase(); 0 is unknown. */
+  unsigned short _cur_column;
+  signed char _vtable_offset;
+  char _shortbuf[1];
+
+  _IO_lock_t *_lock;
+#ifdef _IO_USE_OLD_IO_FILE
+};
+
+struct _IO_FILE_complete
+{
+  struct _IO_FILE _file;
+#endif
+  __off64_t _offset;
+  /* Wide character stream stuff.  */
+  struct _IO_codecvt *_codecvt;
+  struct _IO_wide_data *_wide_data;
+  struct _IO_FILE *_freeres_list;
+  void *_freeres_buf;
+  size_t __pad5;
+  int _mode;
+  /* Make sure we don't get into trouble again.  */
+  char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
+};
+
+/* These macros are used by bits/stdio.h and libio.h.  */
+#define __getc_unlocked_body(_fp)					\
+  (__glibc_unlikely ((_fp)->_IO_read_ptr >= (_fp)->_IO_read_end)	\
+   ? __uflow (_fp) : *(unsigned char *) (_fp)->_IO_read_ptr++)
+
+#define __putc_unlocked_body(_ch, _fp)					\
+  (__glibc_unlikely ((_fp)->_IO_write_ptr >= (_fp)->_IO_write_end)	\
+   ? __overflow (_fp, (unsigned char) (_ch))				\
+   : (unsigned char) (*(_fp)->_IO_write_ptr++ = (_ch)))
+
+#define _IO_EOF_SEEN 0x10
+#define __feof_unlocked_body(_fp) (((_fp)->_flags & _IO_EOF_SEEN) != 0)
+
+#define _IO_ERR_SEEN 0x20
+#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0)
+
+#define _IO_USER_LOCK 0x8000
+/* Many more flag bits are defined internally.  */
+
+#endif
diff --git a/libio/stdio.h b/libio/stdio.h
index 1b4c58aff5..e761c126d5 100644
--- a/libio/stdio.h
+++ b/libio/stdio.h
@@ -845,8 +845,11 @@ extern void funlockfile (FILE *__stream) __THROW;
 # include <bits/getopt_posix.h>
 #endif
 
-/* Internal definitions used by optimizing inlines.  */
-#include <bits/libio.h>
+/* Slow-path routines used by the optimized inline functions in
+   bits/stdio.h.  */
+extern int __underflow (FILE *);
+extern int __uflow (FILE *);
+extern int __overflow (FILE *, int);
 
 /* If we are compiling with optimizing read this file.  It contains
    several optimizing inline functions and macros.  */
