]> pere.pagekite.me Git - homepage.git/blob - blog/data/2010-08-08-fs-sematics.txt
A bit more.
[homepage.git] / blog / data / 2010-08-08-fs-sematics.txt
1 Title: Testing if a file system can be used for home directories...
2 Tags: english, nuug, debian edu
3 Date: 2010-08-08 21:20
4
5 <p>A few years ago, I was involved in a project planning to use
6 Windows file servers as home directory servers for Debian
7 Edu/Skolelinux machines. This was thought to be no problem, as the
8 access would be through the SMB network file system protocol, and we
9 knew other sites used SMB with unix and samba as the file server to
10 mount home directories without any problems. But, after months of
11 struggling, we had to conclude that our goal was impossible.</p>
12
13 <p>The reason is simply that while SMB can be used for home
14 directories when the file server is Samba running on Unix, this only
15 work because of Samba have some extensions and the fact that the
16 underlying file system is a unix file system. When using a Windows
17 file server, the underlying file system do not have POSIX semantics,
18 and several programs will fail if the users home directory where they
19 want to store their configuration lack POSIX semantics.</p>
20
21 <p>As part of this work, I wrote a small C program I want to share
22 with you all, to replicate a few of the problematic applications (like
23 OpenOffice.org and GCompris) and see if the file system was working as
24 it should. If you find yourself in spooky file system land, it might
25 help you find your way out again. This is the fs-test.c source:</p>
26
27 <pre>
28 /*
29 * Some tests to check the file system sematics. Used to verify that
30 * CIFS from a windows server do not work properly as a linux home
31 * directory.
32 * License: GPL v2 or later
33 *
34 * needs libsqlite3-dev and build-essential installed
35 * compile with: gcc -Wall -lsqlite3 -DTEST_SQLITE fs-test.c -o fs-test
36 */
37
38 #define _FILE_OFFSET_BITS 64
39 #define _LARGEFILE_SOURCE 1
40 #define _LARGEFILE64_SOURCE 1
41
42 #define _GNU_SOURCE /* for asprintf() */
43
44 #include &lt;errno.h>
45 #include &lt;fcntl.h>
46 #include &lt;stdio.h>
47 #include &lt;string.h>
48 #include &lt;stdlib.h>
49 #include &lt;sys/file.h>
50 #include &lt;sys/stat.h>
51 #include &lt;sys/types.h>
52 #include &lt;unistd.h>
53
54 #ifdef TEST_SQLITE
55 /*
56 * Test sqlite open, as done by gcompris require the libsqlite3-dev
57 * package and linking with -lsqlite3. A more low level test is
58 * below.
59 * See also &lt;URL: http://www.sqlite.org./faq.html#q5 >.
60 */
61 #include &lt;sqlite3.h>
62 #define CREATE_TABLE_USERS \
63 "CREATE TABLE users (user_id INT UNIQUE, login TEXT, lastname TEXT, firstname TEXT, birthdate TEXT, class_id INT ); "
64 int test_sqlite_open(void) {
65 char *zErrMsg;
66 char *name = "testsqlite.db";
67 sqlite3 *db=NULL;
68 unlink(name);
69 int rc = sqlite3_open(name, &db);
70 if( rc ){
71 printf("error: sqlite open of %s failed: %s\n", name, sqlite3_errmsg(db));
72 sqlite3_close(db);
73 return -1;
74 }
75
76 /* create tables */
77 rc = sqlite3_exec(db,CREATE_TABLE_USERS, NULL, 0, &zErrMsg);
78 if( rc != SQLITE_OK ){
79 printf("error: sqlite table create failed: %s\n", zErrMsg);
80 sqlite3_close(db);
81 return -1;
82 }
83 printf("info: sqlite worked\n");
84 sqlite3_close(db);
85 return 0;
86 }
87 #endif /* TEST_SQLITE */
88
89 /*
90 * Demonstrate locking issue found in gcompris using sqlite3. This
91 * work with ext3, but not with cifs server on Windows 2003. This is
92 * done in the sqlite3 library.
93 * See also
94 * &lt;URL:http://www.cygwin.com/ml/cygwin/2001-08/msg00854.html> and the
95 * POSIX specification
96 * &lt;URL:http://www.opengroup.org/onlinepubs/009695399/functions/fcntl.html>.
97 */
98 int test_gcompris_locking(void) {
99 struct flock fl;
100 char *name = "testsqlite.db";
101 unlink(name);
102 int fd = open(name, O_RDWR|O_CREAT|O_LARGEFILE, 0644);
103 printf("info: testing fcntl locking\n");
104
105 fl.l_whence = SEEK_SET;
106 fl.l_pid = getpid();
107 printf(" Read-locking 1 byte from 1073741824");
108 fl.l_start = 1073741824;
109 fl.l_len = 1;
110 fl.l_type = F_RDLCK;
111 if (0 != fcntl(fd, F_SETLK, &fl) ) printf(" - error!\n"); else printf("\n");
112
113 printf(" Read-locking 510 byte from 1073741826");
114 fl.l_start = 1073741826;
115 fl.l_len = 510;
116 fl.l_type = F_RDLCK;
117 if (0 != fcntl(fd, F_SETLK, &fl) ) printf(" - error!\n"); else printf("\n");
118
119 printf(" Unlocking 1 byte from 1073741824");
120 fl.l_start = 1073741824;
121 fl.l_len = 1;
122 fl.l_type = F_UNLCK;
123 if (0 != fcntl(fd, F_SETLK, &fl) ) printf(" - error!\n"); else printf("\n");
124
125 printf(" Write-locking 1 byte from 1073741824");
126 fl.l_start = 1073741824;
127 fl.l_len = 1;
128 fl.l_type = F_WRLCK;
129 if (0 != fcntl(fd, F_SETLK, &fl) ) printf(" - error!\n"); else printf("\n");
130
131 printf(" Write-locking 510 byte from 1073741826");
132 fl.l_start = 1073741826;
133 fl.l_len = 510;
134 if (0 != fcntl(fd, F_SETLK, &fl) ) printf(" - error!\n"); else printf("\n");
135
136 printf(" Unlocking 2 byte from 1073741824");
137 fl.l_start = 1073741824;
138 fl.l_len = 2;
139 fl.l_type = F_UNLCK;
140 if (0 != fcntl(fd, F_SETLK, &fl) ) printf(" - error!\n"); else printf("\n");
141
142 close(fd);
143 return 0;
144 }
145
146 /*
147 * Test if permissions of freshly created directories allow entries
148 * below them. This was a problem with OpenOffice.org and gcompris.
149 * Mounting with option 'sync' seem to solve this problem while
150 * slowing down file operations.
151 */
152 int test_subdirectory_creation(void) {
153 #define LEVELS 5
154 char *path = strdup("test");
155 char *dirs[LEVELS];
156 int level;
157 printf("info: testing subdirectory creation\n");
158 for (level = 0; level &lt; LEVELS; level++) {
159 char *newpath = NULL;
160 if (-1 == mkdir(path, 0777)) {
161 printf(" error: Unable to create directory '%s': %s\n",
162 path, strerror(errno));
163 break;
164 }
165 asprintf(&newpath, "%s/%s", path, "test");
166 free(path);
167 path = newpath;
168 }
169 return 0;
170 }
171
172 /*
173 * Test if symlinks can be created. This was a problem detected with
174 * KDE.
175 */
176 int test_symlinks(void) {
177 printf("info: testing symlink creation\n");
178 unlink("symlink");
179 if (-1 == symlink("file", "symlink"))
180 printf(" error: Unable to create symlink\n");
181 return 0;
182 }
183
184 int main(int argc, char **argv) {
185 printf("Testing POSIX/Unix sematics on file system\n");
186 test_symlinks();
187 test_subdirectory_creation();
188 #ifdef TEST_SQLITE
189 test_sqlite_open();
190 #endif /* TEST_SQLITE */
191 test_gcompris_locking();
192 return 0;
193 }
194 </pre>
195
196 <p>When everything is working, it should print something like
197 this:</p>
198
199 <pre>
200 Testing POSIX/Unix sematics on file system
201 info: testing symlink creation
202 info: testing subdirectory creation
203 info: sqlite worked
204 info: testing fcntl locking
205 Read-locking 1 byte from 1073741824
206 Read-locking 510 byte from 1073741826
207 Unlocking 1 byte from 1073741824
208 Write-locking 1 byte from 1073741824
209 Write-locking 510 byte from 1073741826
210 Unlocking 2 byte from 1073741824
211 </pre>
212
213 <p>I do not remember the exact details of the problems we saw, but one
214 of them was with locking, where if I remember correctly, POSIX allow a
215 read-only lock to be upgraded to a read-write lock without unlocking
216 the read-only lock (while Windows do not). Another was a bug in the
217 CIFS/SMB client implementation in the Linux kernel where directory
218 meta information would be wrong for a fraction of a second, making
219 OpenOffice.org fail to create its deep directory tree because it was
220 not allowed to create files in its freshly created directory.</p>
221
222 <p>Anyway, here is a nice tool for your tool box, might you never need
223 it. :)</p>
224
225 <p>Update 2010-08-27: Michael Gebetsroither report that he found the
226 script so useful that he created a GIT repository and stored it in
227 <a href="http://github.com/gebi/fs-test">http://github.com/gebi/fs-test</a>.</p>