This web page describes how to increase the MNAMELEN limit on FreeBSD 4-stable.
Why would you want to do that, and what is MNAMELEN anyway?
Well, MNAMELEN is a constant that specifies the maximum
length (in characters) for mount points and for mounted
filesystem nodes. A mount point is where you
mount something, and a a filesystem node is what you
mount there. Look at the output of df:
Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/da0s1a 99183 38815 52434 43% / /dev/da0s1e 198399 17193 165335 9% /var /dev/da0s1f 2032623 1409744 460270 75% /usr /dev/da0s1g 25625747 16364395 7211293 69% /archive mfs:40 100750 54 100696 0% /tmp procfs 4 4 0 100% /proc fs:/usr/local 2032623 1363256 506758 73% /usr/local fs:/usr/X11R6 2032623 1363256 506758 73% /usr/X11R6 fs:/home 10714032 7119312 2737598 72% /home
The filesystem nodes are displayed in the leftmost
column. As you can see, this can be the path of a local
device node (usually in /dev), remote NFS
host:path specification, an MFS process, or a synthetic
filesystem such as procfs. The mount points
are displayed in the rightmost column. These are always
paths in the local filesystem tree.
Now what is the limit on the lengths of those?
Look at /usr/include/sys/mount.h (this
is an excerpt, with spacing added for readability):
#ifdef __i386__
# define MNAMELEN 80
#endif
#ifdef __alpha__
# define MNAMELEN 72
#endif
This raises two questions: Why do i386 and alpha have different limits? And shouldn't 80 (or even 72) characters be enough for everybody?
For the first question: The value of MNAMELEN is chosen
so that the size of the statfs structure (also
defined in <sys/mount.h>) is exactly
256 bytes, so it will align nicely on memory page
boundaries. The alpha platform is a 64-bit architecture,
so some elements of the statfs structure
take more space. Therefore, MNAMELEN is a bit smaller
in order to compensate for that, so that the overall
size stays 256 bytes.
But still, shouldn't 80 (or 72) characters be more than enough? In the above example, the longest filesystem node takes 14 characters. For most needs, it is indeed enough, but there are cases where you run into trouble.
Suppose there's a big ISP with computing centres in several countries and cities. It has a large network infrastructure with fileserver farms, webhosting farms etc. The names of the fileservers are constructed by using the name of the country and city, and possibly further information such as the room number. For example, this might be the name of a fileserver:
filer08-munich-germany.nas-farm.intranet.isp.com
The space on the fileservers is allocated to various departments of the company. The web hosting department, for example, uses mount points for each virtual webserver (so they can be easily moved from one machine to another):
/vol/vol0/dept730/webhosting/virtual/somecustomersdomainname.net
As you can see, the total filesystem mount specification
would be 113 characters in this case. This is not
a contrived example, but a real-world situation.
Putting CNAMEs into the DNS is not an option, because
DNS is managed by a different department. Hardcoding the
IP address in /etc/hosts would be a gross
hack. Shortening the path isn't possible either, because
it's already used in too many different places.
Replacing the domainname with a number would introduce
a superfluous level of indirection that would just
make administration harder.
So far, the ISP uses only Solaris and Linux machines, which don't have an 80 characters limit. Introducing FreeBSD as an alternative operating system will be pretty hard if you can't even mount some filesystems. 80 characters enough for everybody?
The patch described on this page will increase the limit
to 208 characters (i386) or 200 characters (alpha),
repectively. BUT: It will break
binary compatibility for some programs. Not for all,
but for some. Notably, you'll have to recompile any
non-standard shells such as bash and
zsh, Tools that do things to your file
systems such as backup programs (e.g. Amanda), and
probably a few other things. On the bright side,
you will be able to continue using your old Netscape
4.x binary. ;-)
To be more exact: All programs that use the
statfs(), fstatfs or
fhstatfs() system calls will break,
i.e. they will crash with signal 11 (SIGSEGV).
You will have to recompile them from source.
If the source code is not available, you've got
a problem.
Of course, everything you do, you do it on your own risk. If it blows up your machine, don't blame me. You have been warned. If you're not familiar with compiling kernels and with the "make world" process, don't do it.
Before starting, make a backup of all your data. Be prepared to re-install the machine from scratch if something goes wrong.
The following has been tested on on 4.6-stable (as of 2002-08-02), but it should work the same on any later version on the 4-stable branch.
First, make sure you have all the sources in
/usr/src. This should be the same
version as your currently running system. Don't
try to combine an upgrade with this patch, as it
would make things more complicated, and it would
increase the risk that it breaks somewhere.
Update first (the normal way), then continue.
Apply the following patch to
/usr/src/sys/sys/mount.h. You can
download the patch
here (probably better than copy&paste it from the
page, which would destroy tabs).
--- mount.h.orig Sat Sep 14 17:38:17 2002
+++ mount.h Sat Sep 14 17:38:31 2002
@@ -70,10 +70,10 @@
#define MFSNAMELEN 16 /* length of fs type name, including null */
#ifdef __i386__
-#define MNAMELEN 80 /* length of buffer for returned name */
+#define MNAMELEN 208 /* length of buffer for returned name */
#endif
#ifdef __alpha__
-#define MNAMELEN 72 /* length of buffer for returned name */
+#define MNAMELEN 200 /* length of buffer for returned name */
#endif
struct statfs {
Also copy the patched file to /usr/include/sys/mount.h.
Actually that shouldn't be necessary, as the build process should
not use it, but you never know.
Now start the standard update procedure:
cd /usr/src
make buildworld
make buildkernel KERNCONF=YOUR_KERNEL_HERE
make installkernel KERNCONF=YOUR_KERNEL_HERE
Now it gets a little more complicated. You cannot
make the "installworld" in multi-user mode, because of the
binary incompatibilities of the new world. But for the same
reason, you cannot make it in single-user mode directly
either -- you wouldn't even be able to use the
fsck and mount commands.
There are several possible solutions. If you have another
FreeBSD machine, you could plug the harddisk into it and
make the installworld there with DESTDIR=/foo
(whith /foo being the directory where you've mounted the
harddisk). Another possibility is boot from a Live-FS
CD-ROM ("Fixit" CD), mount everything somewhere and do
the installworld. I haven't tried any of those ways, but
they should work.
The following description applies if you don't have a second machine, and you cannot (or don't want to) boot from a CD-ROM.
First, you'll need a few binaries to bootstrap single-user
mode with the new kernel. Copy them from the object tree
to your /root directory. These are the
binaries that you will need (hopefully I didn't forget
any):
/usr/obj/usr/src/sbin/fsck/fsck
/usr/obj/usr/src/sbin/mount/mount
/usr/obj/usr/src/usr.bin/xinstall/xinstall
/usr/obj/usr/src/bin/sh/sh
Additionally, copy the xinstall binary to
/usr/obj/usr/src/i386/usr/bin/install (note, there's
no "x" in the target, just "install"). Don't ask me
why, but it's necessary.
Now it's time to reboot. Note that it is not sufficient
to shutdown into single-user mode. You have to reboot
the machine to enable the new kernel. Be sure to reboot
into single-user mode, i.e. abort the bootloader countdown
with the space key and type "boot -s" at
the boot loader prompt.
When the init(8) process asks for the single-user mode shell,
you have to use the new sh binary, therefore answer
"/root/sh".
First check the filesystems and mount those that your need. You have to use the new binaries:
# /root/fsck -p
# /root/mount -u -o rw /
# /root/mount /usr
If you have /usr/src or /usr/obj on
separate partitions, mount them also.
Note: This is the point of no return.
You can still boot /kernel.old, and you still
haven't overwritten anything of your userland. If you
proceed now, your userland will be overwritten with the
new (incompatible) binaries. The only way back is to
revert the patch to mount.h and repeat the
whole process, or re-install the machine from scratch.
Copy the new binaries that you have stored in
/root into your system:
# cp /root/sh /bin
# cp /root/xinstall /usr/bin/install
Next, disable the installation of perl, because it will break. Again, don't ask me why, but trust me, it will break. Don't worry, you can install it later after the rest of the system has been installed properly. The following command will do.
# echo "NOPERL=true" >> /etc/make.conf
Now initiate the installation and keep your fingers crossed:
# cd /usr/src
# make installworld
If something breaks along the way, you will probably
see a kernel message saying that some program died
with signal 11 (SIGSEGV). If that happens, copy that
binary from the object tree (/usr/obj/usr/src/...)
to the final location on your system, and let me know
about it so I can update this webpage. Then just
restart the "installworld".
If everything went fine, then remove the "NOPERL" line
from /etc/make.conf and install perl.
If that doesn't work, try this:
# cd /usr/src/gnu/usr.bin/perl
# make clean
# cd /usr/src
# make -f Makefile.inc1 _libraries
# make -f Makefile.inc1 _depend
# make -f Makefile.inc1 everything
# make installworld
There's probably a more elegant solution, but the above will work. Alternatively you can install perl from the ports collection, of course.
You're now ready to go multi-user by exitting then single-user mode shell. The next thing you should do is to recompile a few ports. For example, non-standard shells will need recompilation.