1 /* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
7 * This library is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
12 * This library is distributed in the hope that it will be useful, but
13 * without any warranty; without even the implied warranty of merchantability
14 * or fitness for a particular purpose. See the GNU Lesser General Public
15 * License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 #include "daemon_debug.h"
27 #include "nfs41_ops.h"
28 #include "from_kernel.h"
32 #define SBLVL 3 /* dprintf level for superblock logging */
35 static __inline
int compare_fsid(
36 IN
const nfs41_fsid
*lhs
,
37 IN
const nfs41_fsid
*rhs
)
39 if (lhs
->major
> rhs
->major
) return 1;
40 if (lhs
->major
< rhs
->major
) return -1;
41 if (lhs
->minor
> rhs
->minor
) return 1;
42 if (lhs
->minor
< rhs
->minor
) return -1;
47 /* nfs41_superblock */
48 static int superblock_create(
49 IN
const nfs41_fsid
*fsid
,
50 OUT nfs41_superblock
**superblock_out
)
52 int status
= NO_ERROR
;
53 nfs41_superblock
*superblock
;
55 dprintf(SBLVL
, "creating superblock for fsid(%llu,%llu)\n",
56 fsid
->major
, fsid
->minor
);
58 superblock
= calloc(1, sizeof(nfs41_superblock
));
59 if (superblock
== NULL
) {
60 status
= GetLastError();
61 eprintf("failed to allocate superblock "
62 "for fsid(%llu,%llu)\n", fsid
->major
, fsid
->minor
);
66 memcpy(&superblock
->fsid
, fsid
, sizeof(nfs41_fsid
));
67 InitializeSRWLock(&superblock
->lock
);
69 *superblock_out
= superblock
;
74 static int get_superblock_attrs(
75 IN nfs41_session
*session
,
76 IN nfs41_superblock
*superblock
,
77 IN nfs41_path_fh
*file
)
79 bool_t supports_named_attrs
;
82 nfs41_file_info info
= { 0 };
84 attr_request
.arr
[0] = FATTR4_WORD0_SUPPORTED_ATTRS
|
85 FATTR4_WORD0_LINK_SUPPORT
| FATTR4_WORD0_SYMLINK_SUPPORT
|
86 FATTR4_WORD0_ACLSUPPORT
| FATTR4_WORD0_CANSETTIME
|
87 FATTR4_WORD0_CASE_INSENSITIVE
| FATTR4_WORD0_CASE_PRESERVING
|
88 FATTR4_WORD0_MAXREAD
| (uint32_t)(FATTR4_WORD0_MAXWRITE
);
89 attr_request
.arr
[1] = FATTR4_WORD1_FS_LAYOUT_TYPE
|
90 FATTR4_WORD1_TIME_DELTA
;
91 attr_request
.arr
[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT
;
92 attr_request
.count
= 3;
94 info
.supported_attrs
= &superblock
->supported_attrs
;
95 info
.suppattr_exclcreat
= &superblock
->suppattr_exclcreat
;
96 info
.time_delta
= &superblock
->time_delta
;
98 status
= nfs41_superblock_getattr(session
, file
,
99 &attr_request
, &info
, &supports_named_attrs
);
101 eprintf("nfs41_superblock_getattr() failed with %s when fetching "
102 "attributes for fsid(%llu,%llu)\n", nfs_error_string(status
),
103 superblock
->fsid
.major
, superblock
->fsid
.minor
);
108 superblock
->maxread
= info
.maxread
;
110 superblock
->maxread
= session
->fore_chan_attrs
.ca_maxresponsesize
;
113 superblock
->maxwrite
= info
.maxwrite
;
115 superblock
->maxwrite
= session
->fore_chan_attrs
.ca_maxrequestsize
;
117 superblock
->layout_types
= info
.fs_layout_types
;
118 superblock
->aclsupport
= info
.aclsupport
;
119 superblock
->link_support
= info
.link_support
;
120 superblock
->symlink_support
= info
.symlink_support
;
121 superblock
->ea_support
= supports_named_attrs
;
122 superblock
->case_preserving
= info
.case_preserving
;
123 superblock
->case_insensitive
= info
.case_insensitive
;
125 if (bitmap_isset(&info
.attrmask
, 0, FATTR4_WORD0_CANSETTIME
))
126 superblock
->cansettime
= info
.cansettime
;
127 else /* cansettime is not supported, try setting them anyway */
128 superblock
->cansettime
= 1;
130 /* if time_delta is not supported, default to 1s */
131 if (!bitmap_isset(&info
.attrmask
, 1, FATTR4_WORD1_TIME_DELTA
))
132 superblock
->time_delta
.seconds
= 1;
134 /* initialize the default getattr mask */
135 superblock
->default_getattr
.count
= 2;
136 superblock
->default_getattr
.arr
[0] = FATTR4_WORD0_TYPE
137 | FATTR4_WORD0_CHANGE
| FATTR4_WORD0_SIZE
138 | FATTR4_WORD0_FILEID
| FATTR4_WORD0_HIDDEN
139 | FATTR4_WORD0_ARCHIVE
;
140 superblock
->default_getattr
.arr
[1] = FATTR4_WORD1_MODE
141 | FATTR4_WORD1_NUMLINKS
| FATTR4_WORD1_SYSTEM
142 | FATTR4_WORD1_TIME_ACCESS
| FATTR4_WORD1_TIME_CREATE
143 | FATTR4_WORD1_TIME_MODIFY
;
144 superblock
->default_getattr
.arr
[2] = 0;
146 nfs41_superblock_supported_attrs(superblock
, &superblock
->default_getattr
);
148 dprintf(SBLVL
, "attributes for fsid(%llu,%llu): "
149 "maxread=%llu, maxwrite=%llu, layout_types: 0x%X, "
150 "cansettime=%u, time_delta={%llu,%u}, aclsupport=%u, "
151 "link_support=%u, symlink_support=%u, case_preserving=%u, "
152 "case_insensitive=%u\n",
153 superblock
->fsid
.major
, superblock
->fsid
.minor
,
154 superblock
->maxread
, superblock
->maxwrite
,
155 superblock
->layout_types
, superblock
->cansettime
,
156 superblock
->time_delta
.seconds
, superblock
->time_delta
.nseconds
,
157 superblock
->aclsupport
, superblock
->link_support
,
158 superblock
->symlink_support
, superblock
->case_preserving
,
159 superblock
->case_insensitive
);
164 void nfs41_superblock_fs_attributes(
165 IN
const nfs41_superblock
*superblock
,
166 OUT PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
)
168 FsAttrs
->FileSystemAttributes
= FILE_SUPPORTS_REMOTE_STORAGE
;
169 if (superblock
->link_support
)
170 FsAttrs
->FileSystemAttributes
|= FILE_SUPPORTS_HARD_LINKS
;
171 if (superblock
->symlink_support
)
172 FsAttrs
->FileSystemAttributes
|= FILE_SUPPORTS_REPARSE_POINTS
;
173 if (superblock
->ea_support
)
174 FsAttrs
->FileSystemAttributes
|= FILE_SUPPORTS_EXTENDED_ATTRIBUTES
;
175 if (superblock
->case_preserving
)
176 FsAttrs
->FileSystemAttributes
|= FILE_CASE_PRESERVED_NAMES
;
177 if (!superblock
->case_insensitive
)
178 FsAttrs
->FileSystemAttributes
|= FILE_CASE_SENSITIVE_SEARCH
;
179 if (superblock
->aclsupport
)
180 FsAttrs
->FileSystemAttributes
|= FILE_PERSISTENT_ACLS
;
182 FsAttrs
->MaximumComponentNameLength
= NFS41_MAX_COMPONENT_LEN
;
184 /* let the driver fill in FileSystemName */
185 FsAttrs
->FileSystemNameLength
= 0;
187 dprintf(SBLVL
, "FileFsAttributeInformation: case_preserving %u, "
188 "case_insensitive %u, max component %u\n",
189 superblock
->case_preserving
, superblock
->case_insensitive
,
190 FsAttrs
->MaximumComponentNameLength
);
194 /* nfs41_superblock_list */
195 #define superblock_entry(pos) list_container(pos, nfs41_superblock, entry)
197 static int superblock_compare(
198 const struct list_entry
*entry
,
201 const nfs41_superblock
*superblock
= superblock_entry(entry
);
202 return compare_fsid(&superblock
->fsid
, (const nfs41_fsid
*)value
);
205 static nfs41_superblock
* find_superblock(
206 IN nfs41_superblock_list
*superblocks
,
207 IN
const nfs41_fsid
*fsid
)
209 struct list_entry
*entry
;
210 entry
= list_search(&superblocks
->head
, fsid
, superblock_compare
);
211 return entry
? superblock_entry(entry
) : NULL
;
214 void nfs41_superblock_list_init(
215 IN nfs41_superblock_list
*superblocks
)
217 list_init(&superblocks
->head
);
218 InitializeSRWLock(&superblocks
->lock
);
221 void nfs41_superblock_list_free(
222 IN nfs41_superblock_list
*superblocks
)
224 struct list_entry
*entry
, *tmp
;
226 dprintf(SBLVL
, "nfs41_superblock_list_free()\n");
228 list_for_each_tmp(entry
, tmp
, &superblocks
->head
)
229 free(superblock_entry(entry
));
233 int nfs41_superblock_for_fh(
234 IN nfs41_session
*session
,
235 IN
const nfs41_fsid
*fsid
,
236 IN
const nfs41_fh
*parent OPTIONAL
,
237 OUT nfs41_path_fh
*file
)
239 int status
= NFS4_OK
;
240 nfs41_server
*server
= client_server(session
->client
);
241 nfs41_superblock_list
*superblocks
= &server
->superblocks
;
242 nfs41_superblock
*superblock
;
244 dprintf(SBLVL
, "--> nfs41_superblock_for_fh(fsid(%llu,%llu))\n",
245 fsid
->major
, fsid
->minor
);
247 /* compare with the parent's fsid, and use that if it matches */
248 if (parent
&& parent
->superblock
&&
249 compare_fsid(fsid
, &parent
->superblock
->fsid
) == 0) {
250 file
->fh
.superblock
= parent
->superblock
;
251 dprintf(SBLVL
, "using superblock from parent\n");
255 /* using a shared lock, search for an existing superblock */
256 AcquireSRWLockShared(&superblocks
->lock
);
257 superblock
= find_superblock(superblocks
, fsid
);
258 ReleaseSRWLockShared(&superblocks
->lock
);
261 dprintf(SBLVL
, "found existing superblock in server list "
264 AcquireSRWLockExclusive(&superblocks
->lock
);
265 /* must search again under an exclusive lock, in case another thread
266 * created it after our first search */
267 superblock
= find_superblock(superblocks
, fsid
);
269 dprintf(SBLVL
, "found newly created superblock in server list "
270 "[exclusive lock]\n");
272 /* create the superblock */
273 status
= superblock_create(fsid
, &superblock
);
274 if (status
== NO_ERROR
) /* add it to the list */
275 list_add_tail(&superblocks
->head
, &superblock
->entry
);
277 ReleaseSRWLockExclusive(&superblocks
->lock
);
280 if (status
== NO_ERROR
&& superblock
->supported_attrs
.count
== 0) {
281 /* exclusive lock on the superblock while fetching attributes */
282 AcquireSRWLockExclusive(&superblock
->lock
);
283 if (superblock
->supported_attrs
.count
== 0)
284 status
= get_superblock_attrs(session
, superblock
, file
);
285 ReleaseSRWLockExclusive(&superblock
->lock
);
288 file
->fh
.superblock
= superblock
;
290 dprintf(SBLVL
, "<-- nfs41_superblock_for_fh() returning %p, status %d\n",
291 file
->fh
.superblock
, status
);
295 void nfs41_superblock_space_changed(
296 IN nfs41_superblock
*superblock
)
298 /* invalidate cached volume size attributes */
299 AcquireSRWLockExclusive(&superblock
->lock
);
300 superblock
->cache_expiration
= 0;
301 ReleaseSRWLockExclusive(&superblock
->lock
);