From: "J. Bruce Fields" <bfields@fieldses.org>
To: Peter Staubach <staubach@redhat.com>
Cc: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
linux-nfs@vger.kernel.org,
Andrew Morton <akpm@linux-foundation.org>,
Trond Myklebust <trond.myklebust@fys.uio.no>,
linux-fsdevel <linux-fsdevel@vger.kernel.org>
Subject: Re: [PATCH 0/3] enhanced ESTALE error handling
Date: Fri, 18 Jan 2008 10:46:07 -0500 [thread overview]
Message-ID: <20080118154607.GA4976@fieldses.org> (raw)
In-Reply-To: <4790C756.2040704@redhat.com>
On Fri, Jan 18, 2008 at 10:35:50AM -0500, Peter Staubach wrote:
> Hi.
>
> Here is a patch set which modifies the system to enhance the
> ESTALE error handling for system calls which take pathnames
> as arguments.
I think your cover letter may be bigger than any of the actual
patches.... I'm not complaining! But would it be worth adding this
explanation and test code to Documentation/filesystems/ just to keep it
around?
--b.
>
> The error, ESTALE, was originally introduced to handle the
> situation where a file handle, which NFS uses to uniquely
> identify a file on the server, no longer refers to a valid file
> on the server. This can happen when the file is removed on the
> server, either by an application on the server, some other
> client accessing the server, or sometimes even by another
> mounted file system from the same client. It can also happen
> when the file resides upon a file system which is no longer
> exported.
>
> The error, ESTALE, is usually seen when cached directory
> information is used to convert a pathname to a dentry/inode pair.
> The information is discovered to be out of date or stale when a
> subsequent operation is sent to the NFS server. This can easily
> happen in system calls such as stat(2) when the pathname is
> converted a dentry/inode pair using cached information, but then
> a subsequent GETATTR call to the server discovers that the file
> handle is no longer valid.
>
> System calls which take pathnames as arguments should never see
> ESTALE errors from situations like this. These system calls
> should either fail with an ENOENT error if the pathname can not
> be successfully be translated to a dentry/inode pair or succeed
> or fail based on their own semantics.
>
> ESTALE errors which occur during the lookup process can be
> handled by dropping the dentry which refers to the non-existent
> file from the dcache and then restarting the lookup process.
> Care can be taken to ensure that forward progress is always
> being made in order to avoiding infinite loops.
>
> ESTALE errors which occur during operations subsequent to the
> lookup process can be handled by unwinding appropriately and
> then performing the lookup process again. Eventually, either
> the lookup process will succeed or fail correctly or the
> subsequent operation will succeed or fail on its own merits.
>
> This support is desired in order to tighten up recovery from
> discovering stale resources due to the loose cache consistency
> semantics that file systems such as NFS employ. In particular,
> there are several large Red Hat customers, converting from
> Solaris to Linux, who desire this support in order that their
> applications environments continue to work.
>
> Please note that system calls which do not take pathnames as
> arguments or perhaps use file descriptors to identify the
> file to be manipulated may still fail with ESTALE errors.
> There is no recovery possible with these systems calls like
> there is with system calls which take pathnames as arguments.
>
> This support was tested using the attached programs and
> running multiple copies on mounted file systems which do not
> share superblocks. When two or more copies of this program
> are running, many ESTALE errors can be seen over the network.
>
> Comments?
>
> Thanx...
>
> ps
> #
> #define _XOPEN_SOURCE 500
> #define _LARGEFILE64_SOURCE
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <sys/statfs.h>
> #include <sys/inotify.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <signal.h>
>
> void mkdir_test(void);
> void link_test(void);
> void open_test(void);
> void access_test(void);
> void chmod_test(void);
> void chown_test(void);
> void readlink_test(void);
> void utimes_test(void);
> void chdir_test(void);
> void chroot_test(void);
> void rename_test(void);
> void exec_test(void);
> void mknod_test(void);
> void statfs_test(void);
> void truncate_test(void);
> void xattr_test(void);
> void inotify_test(void);
>
> struct tests {
> void (*test)(void);
> };
>
> struct tests tests[] = {
> mkdir_test,
> link_test,
> open_test,
> access_test,
> chmod_test,
> chown_test,
> readlink_test,
> utimes_test,
> chdir_test,
> chroot_test,
> rename_test,
> exec_test,
> mknod_test,
> statfs_test,
> truncate_test,
> xattr_test,
> inotify_test
> };
>
> pid_t test_pids[sizeof(tests) / sizeof(tests[0])];
>
> pid_t parent_pid;
>
> void kill_tests(int);
>
> int
> main(int argc, char *argv[])
> {
> int i;
>
> parent_pid = getpid();
>
> sigset(SIGINT, kill_tests);
>
> sighold(SIGINT);
>
> for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
> test_pids[i] = fork();
> if (test_pids[i] == 0) {
> for (;;)
> (*tests[i].test)();
> /* NOTREACHED */
> }
> }
>
> sigrelse(SIGINT);
>
> pause();
> }
>
> void
> kill_tests(int sig)
> {
> int i;
>
> for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
> if (test_pids[i] != -1) {
> if (kill(test_pids[i], SIGTERM) < 0)
> perror("kill");
> }
> }
>
> exit(0);
> }
>
> void
> check_error(int error, char *operation)
> {
>
> if (error < 0 && errno == ESTALE) {
> perror(operation);
> kill(parent_pid, SIGINT);
> pause();
> }
> }
>
> void
> check_error_child(int error, char *operation)
> {
>
> if (error < 0 && errno == ESTALE) {
> perror(operation);
> kill(parent_pid, SIGINT);
> exit(1);
> }
> }
>
> void
> do_stats(char *file)
> {
> int error;
> struct stat stbuf;
> struct stat64 stbuf64;
>
> error = stat(file, &stbuf);
> check_error(error, "stat");
>
> error = stat64(file, &stbuf64);
> check_error(error, "stat64");
>
> error = lstat(file, &stbuf);
> check_error(error, "lstat");
>
> error = lstat64(file, &stbuf64);
> check_error(error, "lstat64");
> }
>
> void
> do_stats_child(char *file)
> {
> int error;
> struct stat stbuf;
> struct stat64 stbuf64;
>
> error = stat(file, &stbuf);
> check_error_child(error, "stat");
>
> error = stat64(file, &stbuf64);
> check_error_child(error, "stat64");
>
> error = lstat(file, &stbuf);
> check_error_child(error, "lstat");
>
> error = lstat64(file, &stbuf64);
> check_error_child(error, "lstat64");
> }
>
> char *mkdir_dirs[] = {
> "mkdir/a",
> "mkdir/a/b",
> "mkdir/a/b/c",
> "mkdir/a/b/c/d",
> "mkdir/a/b/c/d/e",
> "mkdir/a/b/c/d/e/f",
> "mkdir/a/b/c/d/e/f/g",
> "mkdir/a/b/c/d/e/f/g/h",
> "mkdir/a/b/c/d/e/f/g/h/i",
> "mkdir/a/b/c/d/e/f/g/h/i/j",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z",
> NULL
> };
>
> void
> mkdir_test()
> {
> int i;
> int error;
>
> error = mkdir("mkdir", 0755);
> check_error(error, "mkdir");
>
> for (i = 0; mkdir_dirs[i] != NULL; i++) {
> error = mkdir(mkdir_dirs[i], 0755);
> check_error(error, "mkdir");
> do_stats(mkdir_dirs[i]);
> }
>
> while (--i >= 0) {
> do_stats(mkdir_dirs[i]);
> error = rmdir(mkdir_dirs[i]);
> check_error(error, "rmdir");
> }
>
> error = rmdir("mkdir");
> check_error(error, "rmdir");
> }
>
> char *link_file_a = "link/a";
> char *link_file_b = "link/b";
>
> void
> link_test()
> {
> int error;
> int fd;
>
> error = mkdir("link", 0755);
> check_error(error, "mkdir");
>
> fd = open(link_file_a, O_CREAT, 0644);
> check_error(fd, "open");
>
> (void) close(fd);
>
> do_stats(link_file_a);
>
> error = link(link_file_a, link_file_b);
> check_error(error, "link");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = unlink(link_file_a);
> check_error(error, "unlink");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = link(link_file_b, link_file_a);
> check_error(error, "link");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = unlink(link_file_b);
> check_error(error, "unlink");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = unlink(link_file_a);
> check_error(error, "unlink");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = rmdir("link");
> check_error(error, "rmdir");
> }
>
> char *open_file = "open/a";
>
> void
> open_test()
> {
> int error;
> int fd;
>
> error = mkdir("open", 0755);
> check_error(error, "mkdir");
>
> fd = open(open_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(open_file);
>
> fd = open(open_file, O_RDWR);
> check_error(fd, "open: O_RDWR");
>
> (void) close(fd);
>
> do_stats(open_file);
>
> error = unlink(open_file);
> check_error(error, "unlink");
>
> error = rmdir("open");
> check_error(error, "rmdir");
> }
>
> char *access_file = "access/a";
>
> void
> access_test()
> {
> int error;
> int fd;
>
> error = mkdir("access", 0755);
> check_error(error, "mkdir");
>
> fd = open(access_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(access_file);
>
> error = access(access_file, F_OK);
> check_error(error, "access");
>
> do_stats(access_file);
>
> error = unlink(access_file);
> check_error(error, "unlink");
>
> error = rmdir("access");
> check_error(error, "rmdir");
> }
>
> char *chmod_file = "chmod/a";
>
> void
> chmod_test()
> {
> int error;
> int fd;
>
> error = mkdir("chmod", 0755);
> check_error(error, "mkdir");
>
> fd = open(chmod_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(chmod_file);
>
> error = chmod(chmod_file, 0600);
> check_error(error, "chmod");
>
> do_stats(chmod_file);
>
> error = unlink(chmod_file);
> check_error(error, "unlink");
>
> error = rmdir("chmod");
> check_error(error, "rmdir");
> }
>
> char *chown_file = "chown/a";
>
> void
> chown_test()
> {
> int error;
> int fd;
>
> error = mkdir("chown", 0755);
> check_error(error, "mkdir");
>
> fd = open(chown_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(chown_file);
>
> error = chown(chown_file, 4597, 4597);
> check_error(error, "chown");
>
> do_stats(chown_file);
>
> error = lchown(chown_file, 4596, 4596);
> check_error(error, "lchown");
>
> do_stats(chown_file);
>
> error = unlink(chown_file);
> check_error(error, "unlink");
>
> error = rmdir("chown");
> check_error(error, "rmdir");
> }
>
> char *readlink_file = "readlink/a";
>
> void
> readlink_test()
> {
> int error;
> char buf[BUFSIZ];
>
> error = mkdir("readlink", 0755);
> check_error(error, "mkdir");
>
> error = symlink("b", readlink_file);
> check_error(error, "symlink");
>
> do_stats(readlink_file);
>
> error = readlink(readlink_file, buf, sizeof(buf));
> check_error(error, "readlink");
>
> do_stats(readlink_file);
>
> error = unlink(readlink_file);
> check_error(error, "unlink");
>
> error = rmdir("readlink");
> check_error(error, "rmdir");
> }
>
> char *utimes_file = "utimes/a";
>
> void
> utimes_test()
> {
> int error;
> int fd;
>
> error = mkdir("utimes", 0755);
> check_error(error, "mkdir");
>
> fd = open(utimes_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(utimes_file);
>
> error = utime(utimes_file, NULL);
> check_error(error, "utime");
>
> do_stats(utimes_file);
>
> error = utimes(utimes_file, NULL);
> check_error(error, "utimes");
>
> do_stats(utimes_file);
>
> error = unlink(utimes_file);
> check_error(error, "unlink");
>
> error = rmdir("utimes");
> check_error(error, "rmdir");
> }
>
> char *chdir_dir = "chdir/dir";
>
> void
> chdir_test()
> {
> int error;
> int pid;
> int status;
>
> error = mkdir("chdir", 0755);
> check_error(error, "mkdir");
>
> pid = fork();
> if (pid == 0) {
> error = mkdir(chdir_dir, 0755);
> check_error_child(error, "mkdir");
>
> do_stats_child(chdir_dir);
>
> error = chdir(chdir_dir);
> check_error_child(error, "chdir");
>
> do_stats_child(chdir_dir);
>
> exit(0);
> }
>
> (void) wait(&status);
>
> do_stats(chdir_dir);
>
> error = rmdir(chdir_dir);
> check_error(error, "rmdir");
>
> error = rmdir("chdir");
> check_error(error, "rmdir");
> }
>
> char *chroot_dir = "chroot/dir";
>
> void
> chroot_test()
> {
> int error;
> int pid;
> int status;
>
> error = mkdir("chroot", 0755);
> check_error(error, "mkdir");
>
> pid = fork();
> if (pid == 0) {
> error = mkdir(chroot_dir, 0755);
> check_error_child(error, "mkdir");
>
> do_stats_child(chroot_dir);
>
> error = chroot(chroot_dir);
> check_error_child(error, "chroot");
>
> do_stats_child(chroot_dir);
>
> exit(0);
> }
>
> (void) wait(&status);
>
> do_stats(chroot_dir);
>
> error = rmdir(chroot_dir);
> check_error(error, "rmdir");
>
> error = rmdir("chroot");
> check_error(error, "rmdir");
> }
>
> char *rename_file_a = "rename/a";
> char *rename_file_b = "rename/b";
>
> void
> rename_test()
> {
> int error;
> int fd;
>
> error = mkdir("rename", 0755);
> check_error(error, "mkdir");
>
> fd = open(rename_file_a, O_CREAT, 0644);
> check_error(fd, "open");
>
> (void) close(fd);
>
> do_stats(rename_file_a);
>
> error = rename(rename_file_a, rename_file_b);
> check_error(error, "rename");
>
> do_stats(rename_file_a);
> do_stats(rename_file_b);
>
> error = rename(rename_file_b, rename_file_a);
> check_error(error, "rename");
>
> do_stats(rename_file_a);
> do_stats(rename_file_b);
>
> error = unlink(rename_file_a);
> check_error(error, "unlink");
>
> error = rmdir("rename");
> check_error(error, "rmdir");
> }
>
> char *exec_file = "exec/a";
> char *exec_source_file = "exec_test";
>
> void
> exec_test()
> {
> int error;
> int pid;
> int status;
>
> error = mkdir("exec", 0755);
> check_error(error, "mkdir");
>
> error = link(exec_source_file, exec_file);
> check_error(error, "link");
> do_stats(exec_file);
>
> pid = fork();
> if (pid == 0) {
> error = execl(exec_file, exec_file, NULL);
> check_error_child(error, "execl");
>
> exit(1);
> }
>
> wait(&status);
>
> do_stats(exec_file);
>
> error = unlink(exec_file);
> check_error(error, "unlink");
>
> error = rmdir("exec");
> check_error(error, "rmdir");
> }
>
> char *mknod_file = "mknod/a";
>
> void
> mknod_test()
> {
> int error;
>
> error = mkdir("mknod", 0755);
> check_error(error, "mkdir");
>
> error = mknod(mknod_file, S_IFCHR | 0644, 0);
> check_error(error, "mknod");
>
> do_stats(mknod_file);
>
> error = unlink(mknod_file);
> check_error(error, "unlink");
>
> error = rmdir("mknod");
> check_error(error, "rmdir");
> }
>
> void
> statfs_test()
> {
> int error;
> struct statfs stbuf;
> struct statfs64 stbuf64;
>
> error = mkdir("statfs", 0755);
> check_error(error, "mkdir");
>
> do_stats("statfs");
>
> error = statfs("statfs", &stbuf);
> check_error(error, "statfs");
>
> error = statfs64("statfs", &stbuf64);
> check_error(error, "statfs64");
>
> error = rmdir("statfs");
> check_error(error, "rmdir");
> }
>
> char *truncate_file = "truncate/a";
>
> void
> truncate_test()
> {
> int error;
> int fd;
>
> error = mkdir("truncate", 0755);
> check_error(error, "mkdir");
>
> fd = open(truncate_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(truncate_file);
>
> error = truncate(truncate_file, 1024);
> check_error(error, "truncate");
>
> do_stats(truncate_file);
>
> error = unlink(truncate_file);
> check_error(error, "unlink");
>
> error = rmdir("truncate");
> check_error(error, "rmdir");
> }
>
> char *xattr_file = "xattr/a";
>
> #define ACL_USER_OBJ (0x01)
> #define ACL_USER (0x02)
> #define ACL_GROUP_OBJ (0x04)
> #define ACL_MASK (0x10)
> #define ACL_OTHER (0x20)
>
> struct posix_acl_xattr_entry {
> unsigned short e_tag;
> unsigned short e_perm;
> unsigned int e_id;
> };
>
> #define POSIX_ACL_XATTR_VERSION 0x0002
>
> struct posix_acl_xattr_header {
> unsigned int a_version;
> struct posix_acl_xattr_entry a_entries[5];
> };
>
> void
> xattr_test()
> {
> int error;
> int fd;
> char buf[1024];
> struct posix_acl_xattr_header ents;
>
> error = mkdir("xattr", 0755);
> check_error(error, "mkdir");
>
> fd = open(xattr_file, O_CREAT | O_RDWR, 0444);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(xattr_file);
>
> error = getxattr(xattr_file, "system.posix_acl_access", buf,
> sizeof (buf));
> check_error(error, "getxattr");
> error = lgetxattr(xattr_file, "system.posix_acl_access", buf,
> sizeof (buf));
> check_error(error, "lgetxattr");
>
> ents.a_version = POSIX_ACL_XATTR_VERSION;
> ents.a_entries[0].e_tag = ACL_USER_OBJ;
> ents.a_entries[0].e_perm = 06;
> ents.a_entries[0].e_id = -1;
> ents.a_entries[1].e_tag = ACL_USER;
> ents.a_entries[1].e_perm = 06;
> ents.a_entries[1].e_id = 10;
> ents.a_entries[2].e_tag = ACL_GROUP_OBJ;
> ents.a_entries[2].e_perm = 06;
> ents.a_entries[2].e_id = -1;
> ents.a_entries[3].e_tag = ACL_MASK;
> ents.a_entries[3].e_perm = 06;
> ents.a_entries[3].e_id = -1;
> ents.a_entries[4].e_tag = ACL_OTHER;
> ents.a_entries[4].e_perm = 06;
> ents.a_entries[4].e_id = -1;
>
> error = setxattr(xattr_file, "system.posix_acl_access",
> &ents, sizeof (ents), 0);
> check_error(error, "setxattr");
>
> do_stats(xattr_file);
>
> error = lsetxattr(xattr_file, "system.posix_acl_access",
> &ents, sizeof (ents), 0);
> check_error(error, "lsetxattr");
>
> do_stats(xattr_file);
>
> error = getxattr(xattr_file, "system.posix_acl_access", buf,
> sizeof (buf));
> check_error(error, "getxattr");
> error = lgetxattr(xattr_file, "system.posix_acl_access", buf,
> sizeof (buf));
> check_error(error, "lgetxattr");
>
> error = listxattr(xattr_file, buf, sizeof (buf));
> check_error(error, "listxattr");
> error = llistxattr(xattr_file, buf, sizeof (buf));
> check_error(error, "llistxattr");
>
> error = removexattr(xattr_file, "system.posix_acl_access");
> check_error(error, "removexattr");
>
> do_stats(xattr_file);
>
> error = setxattr(xattr_file, "system.posix_acl_access",
> &ents, sizeof (ents), 0);
> check_error(error, "setxattr");
>
> do_stats(xattr_file);
>
> error = lremovexattr(xattr_file, "system.posix_acl_access");
> check_error(error, "lremovexattr");
>
> do_stats(xattr_file);
>
> error = unlink(xattr_file);
> check_error(error, "unlink");
>
> error = rmdir("xattr");
> check_error(error, "rmdir");
> }
>
> char *inotify_file = "inotify/a";
>
> void
> inotify_test()
> {
> int error;
> int fd;
> int wd;
>
> error = mkdir("inotify", 0755);
> check_error(error, "mkdir");
>
> fd = open(inotify_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(inotify_file);
>
> fd = inotify_init();
> check_error(error, "inotify_init");
>
> do_stats(inotify_file);
>
> wd = inotify_add_watch(fd, inotify_file, IN_ALL_EVENTS);
> check_error(wd, "inotify_add_watch");
>
> do_stats(inotify_file);
>
> error = inotify_rm_watch(fd, wd);
> check_error(error, "inotify_rm_watch");
>
> (void) close(fd);
>
> do_stats(inotify_file);
>
> error = unlink(inotify_file);
> check_error(error, "unlink");
>
> error = rmdir("inotify");
> check_error(error, "rmdir");
> }
> #include <stdlib.h>
>
> main()
> {
> exit(0);
> }
WARNING: multiple messages have this Message-ID (diff)
From: "J. Bruce Fields" <bfields-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
To: Peter Staubach <staubach-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Linux Kernel Mailing List
<linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Andrew Morton
<akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>,
Trond Myklebust
<trond.myklebust-41N18TsMXrtuMpJDpNschA@public.gmane.org>,
linux-fsdevel
<linux-fsdevel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [PATCH 0/3] enhanced ESTALE error handling
Date: Fri, 18 Jan 2008 10:46:07 -0500 [thread overview]
Message-ID: <20080118154607.GA4976@fieldses.org> (raw)
In-Reply-To: <4790C756.2040704-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Fri, Jan 18, 2008 at 10:35:50AM -0500, Peter Staubach wrote:
> Hi.
>
> Here is a patch set which modifies the system to enhance the
> ESTALE error handling for system calls which take pathnames
> as arguments.
I think your cover letter may be bigger than any of the actual
patches.... I'm not complaining! But would it be worth adding this
explanation and test code to Documentation/filesystems/ just to keep it
around?
--b.
>
> The error, ESTALE, was originally introduced to handle the
> situation where a file handle, which NFS uses to uniquely
> identify a file on the server, no longer refers to a valid file
> on the server. This can happen when the file is removed on the
> server, either by an application on the server, some other
> client accessing the server, or sometimes even by another
> mounted file system from the same client. It can also happen
> when the file resides upon a file system which is no longer
> exported.
>
> The error, ESTALE, is usually seen when cached directory
> information is used to convert a pathname to a dentry/inode pair.
> The information is discovered to be out of date or stale when a
> subsequent operation is sent to the NFS server. This can easily
> happen in system calls such as stat(2) when the pathname is
> converted a dentry/inode pair using cached information, but then
> a subsequent GETATTR call to the server discovers that the file
> handle is no longer valid.
>
> System calls which take pathnames as arguments should never see
> ESTALE errors from situations like this. These system calls
> should either fail with an ENOENT error if the pathname can not
> be successfully be translated to a dentry/inode pair or succeed
> or fail based on their own semantics.
>
> ESTALE errors which occur during the lookup process can be
> handled by dropping the dentry which refers to the non-existent
> file from the dcache and then restarting the lookup process.
> Care can be taken to ensure that forward progress is always
> being made in order to avoiding infinite loops.
>
> ESTALE errors which occur during operations subsequent to the
> lookup process can be handled by unwinding appropriately and
> then performing the lookup process again. Eventually, either
> the lookup process will succeed or fail correctly or the
> subsequent operation will succeed or fail on its own merits.
>
> This support is desired in order to tighten up recovery from
> discovering stale resources due to the loose cache consistency
> semantics that file systems such as NFS employ. In particular,
> there are several large Red Hat customers, converting from
> Solaris to Linux, who desire this support in order that their
> applications environments continue to work.
>
> Please note that system calls which do not take pathnames as
> arguments or perhaps use file descriptors to identify the
> file to be manipulated may still fail with ESTALE errors.
> There is no recovery possible with these systems calls like
> there is with system calls which take pathnames as arguments.
>
> This support was tested using the attached programs and
> running multiple copies on mounted file systems which do not
> share superblocks. When two or more copies of this program
> are running, many ESTALE errors can be seen over the network.
>
> Comments?
>
> Thanx...
>
> ps
> #
> #define _XOPEN_SOURCE 500
> #define _LARGEFILE64_SOURCE
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <sys/statfs.h>
> #include <sys/inotify.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <signal.h>
>
> void mkdir_test(void);
> void link_test(void);
> void open_test(void);
> void access_test(void);
> void chmod_test(void);
> void chown_test(void);
> void readlink_test(void);
> void utimes_test(void);
> void chdir_test(void);
> void chroot_test(void);
> void rename_test(void);
> void exec_test(void);
> void mknod_test(void);
> void statfs_test(void);
> void truncate_test(void);
> void xattr_test(void);
> void inotify_test(void);
>
> struct tests {
> void (*test)(void);
> };
>
> struct tests tests[] = {
> mkdir_test,
> link_test,
> open_test,
> access_test,
> chmod_test,
> chown_test,
> readlink_test,
> utimes_test,
> chdir_test,
> chroot_test,
> rename_test,
> exec_test,
> mknod_test,
> statfs_test,
> truncate_test,
> xattr_test,
> inotify_test
> };
>
> pid_t test_pids[sizeof(tests) / sizeof(tests[0])];
>
> pid_t parent_pid;
>
> void kill_tests(int);
>
> int
> main(int argc, char *argv[])
> {
> int i;
>
> parent_pid = getpid();
>
> sigset(SIGINT, kill_tests);
>
> sighold(SIGINT);
>
> for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
> test_pids[i] = fork();
> if (test_pids[i] == 0) {
> for (;;)
> (*tests[i].test)();
> /* NOTREACHED */
> }
> }
>
> sigrelse(SIGINT);
>
> pause();
> }
>
> void
> kill_tests(int sig)
> {
> int i;
>
> for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
> if (test_pids[i] != -1) {
> if (kill(test_pids[i], SIGTERM) < 0)
> perror("kill");
> }
> }
>
> exit(0);
> }
>
> void
> check_error(int error, char *operation)
> {
>
> if (error < 0 && errno == ESTALE) {
> perror(operation);
> kill(parent_pid, SIGINT);
> pause();
> }
> }
>
> void
> check_error_child(int error, char *operation)
> {
>
> if (error < 0 && errno == ESTALE) {
> perror(operation);
> kill(parent_pid, SIGINT);
> exit(1);
> }
> }
>
> void
> do_stats(char *file)
> {
> int error;
> struct stat stbuf;
> struct stat64 stbuf64;
>
> error = stat(file, &stbuf);
> check_error(error, "stat");
>
> error = stat64(file, &stbuf64);
> check_error(error, "stat64");
>
> error = lstat(file, &stbuf);
> check_error(error, "lstat");
>
> error = lstat64(file, &stbuf64);
> check_error(error, "lstat64");
> }
>
> void
> do_stats_child(char *file)
> {
> int error;
> struct stat stbuf;
> struct stat64 stbuf64;
>
> error = stat(file, &stbuf);
> check_error_child(error, "stat");
>
> error = stat64(file, &stbuf64);
> check_error_child(error, "stat64");
>
> error = lstat(file, &stbuf);
> check_error_child(error, "lstat");
>
> error = lstat64(file, &stbuf64);
> check_error_child(error, "lstat64");
> }
>
> char *mkdir_dirs[] = {
> "mkdir/a",
> "mkdir/a/b",
> "mkdir/a/b/c",
> "mkdir/a/b/c/d",
> "mkdir/a/b/c/d/e",
> "mkdir/a/b/c/d/e/f",
> "mkdir/a/b/c/d/e/f/g",
> "mkdir/a/b/c/d/e/f/g/h",
> "mkdir/a/b/c/d/e/f/g/h/i",
> "mkdir/a/b/c/d/e/f/g/h/i/j",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y",
> "mkdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z",
> NULL
> };
>
> void
> mkdir_test()
> {
> int i;
> int error;
>
> error = mkdir("mkdir", 0755);
> check_error(error, "mkdir");
>
> for (i = 0; mkdir_dirs[i] != NULL; i++) {
> error = mkdir(mkdir_dirs[i], 0755);
> check_error(error, "mkdir");
> do_stats(mkdir_dirs[i]);
> }
>
> while (--i >= 0) {
> do_stats(mkdir_dirs[i]);
> error = rmdir(mkdir_dirs[i]);
> check_error(error, "rmdir");
> }
>
> error = rmdir("mkdir");
> check_error(error, "rmdir");
> }
>
> char *link_file_a = "link/a";
> char *link_file_b = "link/b";
>
> void
> link_test()
> {
> int error;
> int fd;
>
> error = mkdir("link", 0755);
> check_error(error, "mkdir");
>
> fd = open(link_file_a, O_CREAT, 0644);
> check_error(fd, "open");
>
> (void) close(fd);
>
> do_stats(link_file_a);
>
> error = link(link_file_a, link_file_b);
> check_error(error, "link");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = unlink(link_file_a);
> check_error(error, "unlink");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = link(link_file_b, link_file_a);
> check_error(error, "link");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = unlink(link_file_b);
> check_error(error, "unlink");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = unlink(link_file_a);
> check_error(error, "unlink");
> do_stats(link_file_a);
> do_stats(link_file_b);
>
> error = rmdir("link");
> check_error(error, "rmdir");
> }
>
> char *open_file = "open/a";
>
> void
> open_test()
> {
> int error;
> int fd;
>
> error = mkdir("open", 0755);
> check_error(error, "mkdir");
>
> fd = open(open_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(open_file);
>
> fd = open(open_file, O_RDWR);
> check_error(fd, "open: O_RDWR");
>
> (void) close(fd);
>
> do_stats(open_file);
>
> error = unlink(open_file);
> check_error(error, "unlink");
>
> error = rmdir("open");
> check_error(error, "rmdir");
> }
>
> char *access_file = "access/a";
>
> void
> access_test()
> {
> int error;
> int fd;
>
> error = mkdir("access", 0755);
> check_error(error, "mkdir");
>
> fd = open(access_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(access_file);
>
> error = access(access_file, F_OK);
> check_error(error, "access");
>
> do_stats(access_file);
>
> error = unlink(access_file);
> check_error(error, "unlink");
>
> error = rmdir("access");
> check_error(error, "rmdir");
> }
>
> char *chmod_file = "chmod/a";
>
> void
> chmod_test()
> {
> int error;
> int fd;
>
> error = mkdir("chmod", 0755);
> check_error(error, "mkdir");
>
> fd = open(chmod_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(chmod_file);
>
> error = chmod(chmod_file, 0600);
> check_error(error, "chmod");
>
> do_stats(chmod_file);
>
> error = unlink(chmod_file);
> check_error(error, "unlink");
>
> error = rmdir("chmod");
> check_error(error, "rmdir");
> }
>
> char *chown_file = "chown/a";
>
> void
> chown_test()
> {
> int error;
> int fd;
>
> error = mkdir("chown", 0755);
> check_error(error, "mkdir");
>
> fd = open(chown_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(chown_file);
>
> error = chown(chown_file, 4597, 4597);
> check_error(error, "chown");
>
> do_stats(chown_file);
>
> error = lchown(chown_file, 4596, 4596);
> check_error(error, "lchown");
>
> do_stats(chown_file);
>
> error = unlink(chown_file);
> check_error(error, "unlink");
>
> error = rmdir("chown");
> check_error(error, "rmdir");
> }
>
> char *readlink_file = "readlink/a";
>
> void
> readlink_test()
> {
> int error;
> char buf[BUFSIZ];
>
> error = mkdir("readlink", 0755);
> check_error(error, "mkdir");
>
> error = symlink("b", readlink_file);
> check_error(error, "symlink");
>
> do_stats(readlink_file);
>
> error = readlink(readlink_file, buf, sizeof(buf));
> check_error(error, "readlink");
>
> do_stats(readlink_file);
>
> error = unlink(readlink_file);
> check_error(error, "unlink");
>
> error = rmdir("readlink");
> check_error(error, "rmdir");
> }
>
> char *utimes_file = "utimes/a";
>
> void
> utimes_test()
> {
> int error;
> int fd;
>
> error = mkdir("utimes", 0755);
> check_error(error, "mkdir");
>
> fd = open(utimes_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(utimes_file);
>
> error = utime(utimes_file, NULL);
> check_error(error, "utime");
>
> do_stats(utimes_file);
>
> error = utimes(utimes_file, NULL);
> check_error(error, "utimes");
>
> do_stats(utimes_file);
>
> error = unlink(utimes_file);
> check_error(error, "unlink");
>
> error = rmdir("utimes");
> check_error(error, "rmdir");
> }
>
> char *chdir_dir = "chdir/dir";
>
> void
> chdir_test()
> {
> int error;
> int pid;
> int status;
>
> error = mkdir("chdir", 0755);
> check_error(error, "mkdir");
>
> pid = fork();
> if (pid == 0) {
> error = mkdir(chdir_dir, 0755);
> check_error_child(error, "mkdir");
>
> do_stats_child(chdir_dir);
>
> error = chdir(chdir_dir);
> check_error_child(error, "chdir");
>
> do_stats_child(chdir_dir);
>
> exit(0);
> }
>
> (void) wait(&status);
>
> do_stats(chdir_dir);
>
> error = rmdir(chdir_dir);
> check_error(error, "rmdir");
>
> error = rmdir("chdir");
> check_error(error, "rmdir");
> }
>
> char *chroot_dir = "chroot/dir";
>
> void
> chroot_test()
> {
> int error;
> int pid;
> int status;
>
> error = mkdir("chroot", 0755);
> check_error(error, "mkdir");
>
> pid = fork();
> if (pid == 0) {
> error = mkdir(chroot_dir, 0755);
> check_error_child(error, "mkdir");
>
> do_stats_child(chroot_dir);
>
> error = chroot(chroot_dir);
> check_error_child(error, "chroot");
>
> do_stats_child(chroot_dir);
>
> exit(0);
> }
>
> (void) wait(&status);
>
> do_stats(chroot_dir);
>
> error = rmdir(chroot_dir);
> check_error(error, "rmdir");
>
> error = rmdir("chroot");
> check_error(error, "rmdir");
> }
>
> char *rename_file_a = "rename/a";
> char *rename_file_b = "rename/b";
>
> void
> rename_test()
> {
> int error;
> int fd;
>
> error = mkdir("rename", 0755);
> check_error(error, "mkdir");
>
> fd = open(rename_file_a, O_CREAT, 0644);
> check_error(fd, "open");
>
> (void) close(fd);
>
> do_stats(rename_file_a);
>
> error = rename(rename_file_a, rename_file_b);
> check_error(error, "rename");
>
> do_stats(rename_file_a);
> do_stats(rename_file_b);
>
> error = rename(rename_file_b, rename_file_a);
> check_error(error, "rename");
>
> do_stats(rename_file_a);
> do_stats(rename_file_b);
>
> error = unlink(rename_file_a);
> check_error(error, "unlink");
>
> error = rmdir("rename");
> check_error(error, "rmdir");
> }
>
> char *exec_file = "exec/a";
> char *exec_source_file = "exec_test";
>
> void
> exec_test()
> {
> int error;
> int pid;
> int status;
>
> error = mkdir("exec", 0755);
> check_error(error, "mkdir");
>
> error = link(exec_source_file, exec_file);
> check_error(error, "link");
> do_stats(exec_file);
>
> pid = fork();
> if (pid == 0) {
> error = execl(exec_file, exec_file, NULL);
> check_error_child(error, "execl");
>
> exit(1);
> }
>
> wait(&status);
>
> do_stats(exec_file);
>
> error = unlink(exec_file);
> check_error(error, "unlink");
>
> error = rmdir("exec");
> check_error(error, "rmdir");
> }
>
> char *mknod_file = "mknod/a";
>
> void
> mknod_test()
> {
> int error;
>
> error = mkdir("mknod", 0755);
> check_error(error, "mkdir");
>
> error = mknod(mknod_file, S_IFCHR | 0644, 0);
> check_error(error, "mknod");
>
> do_stats(mknod_file);
>
> error = unlink(mknod_file);
> check_error(error, "unlink");
>
> error = rmdir("mknod");
> check_error(error, "rmdir");
> }
>
> void
> statfs_test()
> {
> int error;
> struct statfs stbuf;
> struct statfs64 stbuf64;
>
> error = mkdir("statfs", 0755);
> check_error(error, "mkdir");
>
> do_stats("statfs");
>
> error = statfs("statfs", &stbuf);
> check_error(error, "statfs");
>
> error = statfs64("statfs", &stbuf64);
> check_error(error, "statfs64");
>
> error = rmdir("statfs");
> check_error(error, "rmdir");
> }
>
> char *truncate_file = "truncate/a";
>
> void
> truncate_test()
> {
> int error;
> int fd;
>
> error = mkdir("truncate", 0755);
> check_error(error, "mkdir");
>
> fd = open(truncate_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(truncate_file);
>
> error = truncate(truncate_file, 1024);
> check_error(error, "truncate");
>
> do_stats(truncate_file);
>
> error = unlink(truncate_file);
> check_error(error, "unlink");
>
> error = rmdir("truncate");
> check_error(error, "rmdir");
> }
>
> char *xattr_file = "xattr/a";
>
> #define ACL_USER_OBJ (0x01)
> #define ACL_USER (0x02)
> #define ACL_GROUP_OBJ (0x04)
> #define ACL_MASK (0x10)
> #define ACL_OTHER (0x20)
>
> struct posix_acl_xattr_entry {
> unsigned short e_tag;
> unsigned short e_perm;
> unsigned int e_id;
> };
>
> #define POSIX_ACL_XATTR_VERSION 0x0002
>
> struct posix_acl_xattr_header {
> unsigned int a_version;
> struct posix_acl_xattr_entry a_entries[5];
> };
>
> void
> xattr_test()
> {
> int error;
> int fd;
> char buf[1024];
> struct posix_acl_xattr_header ents;
>
> error = mkdir("xattr", 0755);
> check_error(error, "mkdir");
>
> fd = open(xattr_file, O_CREAT | O_RDWR, 0444);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(xattr_file);
>
> error = getxattr(xattr_file, "system.posix_acl_access", buf,
> sizeof (buf));
> check_error(error, "getxattr");
> error = lgetxattr(xattr_file, "system.posix_acl_access", buf,
> sizeof (buf));
> check_error(error, "lgetxattr");
>
> ents.a_version = POSIX_ACL_XATTR_VERSION;
> ents.a_entries[0].e_tag = ACL_USER_OBJ;
> ents.a_entries[0].e_perm = 06;
> ents.a_entries[0].e_id = -1;
> ents.a_entries[1].e_tag = ACL_USER;
> ents.a_entries[1].e_perm = 06;
> ents.a_entries[1].e_id = 10;
> ents.a_entries[2].e_tag = ACL_GROUP_OBJ;
> ents.a_entries[2].e_perm = 06;
> ents.a_entries[2].e_id = -1;
> ents.a_entries[3].e_tag = ACL_MASK;
> ents.a_entries[3].e_perm = 06;
> ents.a_entries[3].e_id = -1;
> ents.a_entries[4].e_tag = ACL_OTHER;
> ents.a_entries[4].e_perm = 06;
> ents.a_entries[4].e_id = -1;
>
> error = setxattr(xattr_file, "system.posix_acl_access",
> &ents, sizeof (ents), 0);
> check_error(error, "setxattr");
>
> do_stats(xattr_file);
>
> error = lsetxattr(xattr_file, "system.posix_acl_access",
> &ents, sizeof (ents), 0);
> check_error(error, "lsetxattr");
>
> do_stats(xattr_file);
>
> error = getxattr(xattr_file, "system.posix_acl_access", buf,
> sizeof (buf));
> check_error(error, "getxattr");
> error = lgetxattr(xattr_file, "system.posix_acl_access", buf,
> sizeof (buf));
> check_error(error, "lgetxattr");
>
> error = listxattr(xattr_file, buf, sizeof (buf));
> check_error(error, "listxattr");
> error = llistxattr(xattr_file, buf, sizeof (buf));
> check_error(error, "llistxattr");
>
> error = removexattr(xattr_file, "system.posix_acl_access");
> check_error(error, "removexattr");
>
> do_stats(xattr_file);
>
> error = setxattr(xattr_file, "system.posix_acl_access",
> &ents, sizeof (ents), 0);
> check_error(error, "setxattr");
>
> do_stats(xattr_file);
>
> error = lremovexattr(xattr_file, "system.posix_acl_access");
> check_error(error, "lremovexattr");
>
> do_stats(xattr_file);
>
> error = unlink(xattr_file);
> check_error(error, "unlink");
>
> error = rmdir("xattr");
> check_error(error, "rmdir");
> }
>
> char *inotify_file = "inotify/a";
>
> void
> inotify_test()
> {
> int error;
> int fd;
> int wd;
>
> error = mkdir("inotify", 0755);
> check_error(error, "mkdir");
>
> fd = open(inotify_file, O_CREAT | O_RDWR, 0644);
> check_error(fd, "open: O_CREAT");
>
> (void) close(fd);
>
> do_stats(inotify_file);
>
> fd = inotify_init();
> check_error(error, "inotify_init");
>
> do_stats(inotify_file);
>
> wd = inotify_add_watch(fd, inotify_file, IN_ALL_EVENTS);
> check_error(wd, "inotify_add_watch");
>
> do_stats(inotify_file);
>
> error = inotify_rm_watch(fd, wd);
> check_error(error, "inotify_rm_watch");
>
> (void) close(fd);
>
> do_stats(inotify_file);
>
> error = unlink(inotify_file);
> check_error(error, "unlink");
>
> error = rmdir("inotify");
> check_error(error, "rmdir");
> }
> #include <stdlib.h>
>
> main()
> {
> exit(0);
> }
-
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2008-01-18 15:46 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-01-18 15:35 [PATCH 0/3] enhanced ESTALE error handling Peter Staubach
2008-01-18 15:46 ` J. Bruce Fields [this message]
2008-01-18 15:46 ` J. Bruce Fields
2008-01-18 16:41 ` Chuck Lever
2008-01-18 16:41 ` Chuck Lever
2008-01-18 16:55 ` Peter Staubach
2008-01-18 16:55 ` Peter Staubach
2008-01-18 17:17 ` Chuck Lever
2008-01-18 17:17 ` Chuck Lever
2008-01-18 17:30 ` Peter Staubach
2008-01-18 17:52 ` Chuck Lever
2008-01-18 18:12 ` Peter Staubach
2008-01-18 18:37 ` J. Bruce Fields
2008-01-18 18:37 ` J. Bruce Fields
2008-01-18 19:12 ` Peter Staubach
2008-01-18 18:17 ` Chuck Lever
2008-02-01 20:57 ` [PATCH 0/3] enhanced ESTALE error handling (v2) Peter Staubach
2008-02-01 20:57 ` Peter Staubach
2008-03-10 20:23 ` [PATCH 0/3] enhanced ESTALE error handling (v3) Peter Staubach
2008-03-10 22:42 ` Andreas Dilger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080118154607.GA4976@fieldses.org \
--to=bfields@fieldses.org \
--cc=akpm@linux-foundation.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=staubach@redhat.com \
--cc=trond.myklebust@fys.uio.no \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.