[Pvfs2-cvs] commit by pcarns in pvfs2-1/src/kernel/linux-2.6: dir.c
CVS commit program
cvs at parl.clemson.edu
Mon Jan 28 13:04:53 EST 2008
Update of /projects/cvsroot/pvfs2-1/src/kernel/linux-2.6
In directory parlweb1:/tmp/cvs-serv1435/src/kernel/linux-2.6
Modified Files:
dir.c
Log Message:
adding a special seek operation for pvfs2 directories. The default vfs seek
doesn't work because we have special meanings for f_pos on directories:
- 0 and 1: fake "." and ".." entries
- PVFS_READDIR_END and PVFS_READDIR_START: special names
- all else: pvfs readdir token value
Who would want to seek on a directory? Well, glibc occasionally decides to
for some reason: glibc-*/sysdeps/unix/sysv/linux/getdents.c. There is still
a flaw in that we can't seek to offset 3 or 4 if someone happens to do that
(see code comments). See this trac entry for how to trigger (and lose dir
entries) on some systems:
https://trac.mcs.anl.gov/projects/pvfs/ticket/11
Index: dir.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/kernel/linux-2.6/dir.c,v
diff -p -u -r1.50 -r1.51
--- dir.c 19 Dec 2007 05:37:36 -0000 1.50
+++ dir.c 28 Jan 2008 18:04:53 -0000 1.51
@@ -878,6 +878,43 @@ static int pvfs2_readdirplus_lite(
}
#endif
+/** Change the file pointer position for an instance of an open dir.
+ *
+ * \note If .llseek is overriden, we must acquire lock as described in
+ * Documentation/filesystems/Locking.
+ */
+loff_t pvfs2_dir_llseek(struct file *file, loff_t offset, int origin)
+{
+ /* offsets 0 and 1 are fine */
+
+ if (origin == SEEK_SET && offset == 2)
+ {
+ gossip_debug(GOSSIP_DIR_DEBUG, "pvfs2_dir_llseek: setting READDIR_START\n");
+ /* offset 2 _really_ means the first true pvfs entry, skip . and .. */
+ offset = PVFS_READDIR_START;
+ }
+ else if (origin == SEEK_SET && ((offset == 3) || (offset == 4)))
+ {
+ /* we don't have any way to specify this; if we set offset to
+ * 0 or 1 then pvfs_readdir() will think you want "." or ".."
+ */
+ gossip_err("PVFS can't seek directories to offset 3 or 4!\n");
+ return(-EINVAL);
+ }
+ else if (origin == SEEK_SET && offset > 4)
+ {
+ gossip_debug(GOSSIP_DIR_DEBUG, "pvfs2_dir_llseek: guessing directory token\n");
+ /* contrive what the pvfs readdir token probably is, assuming that
+ * we need to skip two entries as well */
+ offset -= 3;
+ }
+
+ gossip_debug(GOSSIP_FILE_DEBUG, "pvfs2_dir_llseek: offset is %ld | origin is %d\n",
+ (long)offset, origin);
+
+ return generic_file_llseek(file, offset, origin);
+}
+
/** PVFS2 implementation of VFS directory operations */
struct file_operations pvfs2_dir_operations =
{
@@ -885,7 +922,8 @@ struct file_operations pvfs2_dir_operati
read : generic_read_dir,
readdir : pvfs2_readdir,
open : pvfs2_file_open,
- release : pvfs2_file_release
+ release : pvfs2_file_release,
+ llseek : pvfs2_dir_llseek
#else
.read = generic_read_dir,
.readdir = pvfs2_readdir,
@@ -896,7 +934,8 @@ struct file_operations pvfs2_dir_operati
.readdirplus_lite = pvfs2_readdirplus_lite,
#endif
.open = pvfs2_file_open,
- .release = pvfs2_file_release
+ .release = pvfs2_file_release,
+ .llseek = pvfs2_dir_llseek
#endif
};
More information about the Pvfs2-cvs
mailing list