instead of the srv_open list pointer we were incrementing the main loop
of fcb opens. it lead to an infinite loop when the srv_open list contained
more than 1 entry for a given fcb.
some fileio tests sends a setattr with basicinfo.fileattributes=0
we used to then send a setattr with zero hidden, system, and archive
attrs. instead in this case, we should be keeping the old values
for these attributes.
if we get this error when we are trying to remove the file before
closing (ie windows doesn't allow removal of opened files), we
first send the close and then re-try the remove
opens for create unchecked shouldn't have a non-zero size. if it does
it will either be ignored or flagged as an error.
casey notes that every open of named attributes is a create open.
even though we know the size of the file we are about to write,
we need to truncate it first, as setting the size will be ignored
by the server, leading to keeping the old size.
because there could be lots of rpcs in flight when we get a CB_RECALL_SLOT or NFS4ERR_BADSLOT error, we're likely to get some replies with an old value for target_highest_slotid. added a MAX_SLOTS_DELAY of 2 seconds to ignore changes to target_highest_slotid after CB_RECALL_SLOT or NFS4ERR_BADSLOT to prevent max_slots from jumping around between the old and new values
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
NFS4ERR_BADSLOT indicates that the supplied slotid is outside the server's expected range. update table.max_slots to this value to prevent it from being used again, then acquire a new slot and retry the rpc
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
adds support for CB_RECALL_SLOT with function nfs41_session_recall_slot()
when SEQUENCE or CB_RECALL_SLOT gives us a valid target_highest_slotid, use it to update max_slots
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
due to the slot table's use of CRITICAL_SECTION and CONDITION_VARIABLE, the slot table no longer returns errors for following functions:
nfs41_session_bump_seq()
nfs41_session_free_slot()
nfs41_session_get_slot()
nfs41_session_sequence()
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
changed nfs41_slot_table.lock and .cond to a CRITICAL_SECTION and CONDITION_VARIABLE for use with SleepConditionVariableCS()
added a 'num_used' field to simplify the condition variable's predicate function slot_table_avail()
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
cygwin does geteas for regular files and asks for nfssymlinktargetname for
which we were doing an upcall and failing nfs41_readlink() with err_invalid.
instead check that it's not a symlink in the driver and reply as we used to
with 0 eavaluelenth
i meant to separate this commit into two but started doing code
changes after the "1st" commit. it'll be too much work to undo.
so...
1. most of the changes are cosmetic changes that cleanuped some line.
2. code changes: remove filename from individual unions since we have
a global one in the upcalldowncall_entry already.
when cygwin attempts to open a file for DELETE access, assume that it means to open the link itself. this avoids making the first open upcall to set up the reparse, only to see RxPrepareToReparseSymbolicLink() return ReparseRequired=FALSE
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
according to msdn documentation for RxPrepareToReparseSymbolicLink(), setting ReparseRequired=FALSE means that the link itself should be opened instead of its target. this shows up when cygwin attempts to delete or rename a symbolic link, because it doesn't open the file with the FILE_OPEN_REPARSE_POINT flag
when RxPrepareToReparseSymbolicLink() returns success but with ReparseRequired=FALSE, set the FILE_OPEN_REPARSE_POINT flag and resend the open upcall
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
handles the query for NfsSymlinkTargetName EA by making a symlink upcall. adds a trailing null for 'ls -l' in cygwin
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
when given a NfsSymlinkTargetName EA on create, marshall the unicode target name to the daemon, which issues a CREATE rpc to create the symlink
modified the driver's marshall_unicode_as_utf8() function to handle the NULL string buffer for non-symlink opens
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
test cases 208, 219, 221 of fileio were failing if rdbss caching was
turned on. the reason was, on reopen of a file, rdbss had cached,
unflushed data yet so reopen had incorrect view of the file.
need to invalidate the cache even if the open didn't return a
different change attribute than the one stored in the fcb, unfortunately.
macros now expect a non-pointer argument for pList
removed unused pList argument from nfs41_Removeentry()
call to IsListEmpty(&pNetRootContext->mounts.head) changed to nfs41_IsListEmpty() which does locking
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
is_root_directory() was failing to take mount paths into account, causing it to ignore the cached volume attributes and make unnecessary upcalls when a mount path was specified
because the mount path is only available during nfs41_CreateVNetRoot(), its length is now saved in the new field NFS41_V_NET_ROOT_EXTENSION.MountPathLen for use in is_root_directory()
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This reverts commit 7f338d871b.
now that each VNetRoot makes a MOUNT upcall and fetches fs attributes for its mount path, we no longer need to save fs attributes with the NetRoot
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
even if CreateVNetRoot() finds an existing compatible mount, make a MOUNT upcall and pass that session to the daemon. the daemon can avoid creating a new root/client/seession, but still has a chance to verify the mount path with LOOKUPs and fetch fs attributes for the new VNetRoot
when the daemon is given an existing root, handle_mount() avoids any extra reference counting on it. while we can make multiple MOUNT upcalls on a shared mount, we'll still only send the one UNMOUNT upcall on FinalizeNetRoot()
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
COMMIT-to-ds: if pnfs_write() finds that its data server requests weren't written stably, it must fail with PNFSERR_IO instead of sending a COMMIT to the mds. mds COMMITs can only be used for mds WRITEs in this configuration
COMMIT-to-mds: the mds and data servers are required to use a common write/commit verifier, so the mds COMMIT's verifier must be checked against all ds verifiers
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
layout status flags for PNFS_LAYOUT_RECALLED and PNFS_LAYOUT_CHANGED are removed, and replaced by a list of recalled ranges. recalls during io are added to the list and processed on pnfs_layout_io_finished(). recalls outside of io are processed immediately
new function layout_recall_range() loops through all existing layout segments, and removes ranges that intersect with the range recalled. deals with 4 cases per segment:
-only the beginning of the segment is recalled
-only the end of the segment is recalled
-the entire segment is recalled
-only a middle part of the segment is recalled
new function pnfs_layout_recall_status() is called before each unit of io, allowing io threads to bail out early if a recall is detected. takes a layout segment as an argument, and only returns an error if that segment intersects a recalled range
new function pnfs_layout_recall_fenced() is called when map_ds_error() in pnfs_io.c detects fencing. also takes a layout segment as an argument, and appends a recall matching the range of the segment
pnfs_layout_state_prepare() now checks the given range against the list of recalled ranges
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
when processing new layout segments from a LAYOUTGET response, layout_update_range() first attempts to merge each new segment into existing segments before calling layout_ordered_insert(). two segments are eligible for merging if their ranges overlap, and all other relevant fields (iomode, stripe unit, deviceid, filehandles, etc) match
when a new segment is merged with an existing segment, the existing segment's extended range may cause it to overlap with another existing segment; additional merging may then be necessary. but merging an existing segment with another existing segment results in the the first segment being removed/freed, so this type of merging can -only- be performed when no io threads are referencing the layout. pnfs_layout_io_finished() calls layout_state_merge() to finish any merging that was delayed during io
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
pnfs_layout_state now stores a list instead of a single pnfs_file_layout entry. when new segments are acquired through LAYOUTGET, they are inserted into the list in order of increasing offset
functions related to pnfs_layout_state_prepare() now operate on the list to find missing layout ranges and segments missing devices
pattern_init() in pnfs_io.c now allocates and initializes io threads for each layout segment in the range
new function pattern_join() will call WaitForMultipleObjects() in a loop, to support io patterns with more than 64 threads. if pattern_fork() is called with a thread count of 1, the thread function is called directly instead of spawning a new thread
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
struct pnfs_io_pattern, pnfs_io_thread, and pnfs_io_unit are not referenced outside of pnfs_io.c, so they don't need to be in pnfs.h
also grouped the inline helper functions together at the bottom of pnfs.h
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
added stripe_next_unit() in pnfs_io.c, removed pnfs_file_device_io_unit() from pnfs_device.c
moved get_sparse_fh()/get_dense_fh() to pnfs_io.c, now only called once on pattern_init()
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
when starting io, both pnfs_read() and pnfs_write() need a guarantee that their range is covered by layout segments. because we have to drop the lock for LAYOUTGET and GETDEVICEINFO, earlier layout segments may be recalled during this process. to avoid this, new function pnfs_layout_state_prepare() gets called repeatedly until it can verify under a single lock that 1) the entire desired range is covered with layouts and 2) each of these layouts has an associated device. whenever pnfs_layout_state_prepare() has to drop its lock for LAYOUTGET or GETDEVICEINFO, it returns PNFS_PENDING
on PNFS_SUCCESS, the caller knows that all segments in the range are valid and can dispatch io to those segments without worrying about recalls, because it still holds the pnfs_layout_state lock
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
nfs41_open_state stores current ea index, and increments it for each successful entry returned. index is set to 0 when the 'restart' argument is given. cached directory listing is freed after the listing is complete
QueryEaInfo now sends up its output buffer size, and the daemon uses this to limit its results. added checks for buffer overflows, which required changes to the downcall structure
updated driver error mappings for map_setea_error()
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
when given a null for FILE_GET_EA_INFORMATION, use READDIR to construct one with
the full named attribute directory listing
new function read_entire_dir() allocates an initial buffer for readdir entries a
nd calls nfs41_readdir() repeatedly to fill it. the buffer is realloc()ed as mo
re space is required, allowing the function to return a complete listing in a si
ngle buffer
new function calculate_ea_list_length() calculates the exact length of the FILE_
GET_EA_INFORMATION buffer required to hold all of the names from the directory l
isting
once the FILE_GET_EA_INFORMATION buffer is allocated, it is filled by populate_e
a_list() and cached with nfs41_open_state
handle_getexattr() remains largely unchanged
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
check_nfs41_queryea_args() will now accept EaList == NULL, unless EAs are unsupported
moved handling of cygwin EAs to new function QueryCygwinEA()
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
when open is given an ea buffer, pass it to new function nfs41_ea_set() after successful file creation. matches NTFS behavior on all dispositions: sets EAs on FILE_CREATE, FILE_OVERWRITE, FILE_OVERWRITE_IF, FILE_SUPERSEDE. does not set EAs on FILE_OPEN. only sets EAs on FILE_OPEN_IF if file did not previously exist. see new function create_with_ea()
nfs41_ea_set() returns nfs error codes. uses NFS4ERR_FBIG when the EaValueLength exceeds NFS4_EASIZE (256). this gets mapped to windows error ERROR_FILE_TOO_LARGE, which the driver now converts to STATUS_EA_TOO_LARGE
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
if an EA buffer is given on create, map it to use space and pass
it to the daemon
removed check for FILE_WRITE_EA permission; it isn't required on ntfs
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
nfs_ea <filename> create <name> <value>
nfs_ea <filename> set <name> [value]
nfs_ea <filename> get <name> [name...]
nfs_ea <filename> list
Note that the test uses NtCreateFile(), so filenames must be specified in NT format: \??\z:\foo
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
adds a critical section to nfs41_open_state. this lock is taken before generating the stateid/seqid, and released after updated stateid is saved to nfs41_open_state
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>