Linux 2.2.0
[davej-history.git] / fs / smbfs / file.c
bloba6cf24ce1714cd040a02f66ad81e7cbd661ccba3
1 /*
2 * file.c
4 * Copyright (C) 1995, 1996, 1997 by Paal-Kr. Engstad and Volker Lendecke
5 * Copyright (C) 1997 by Volker Lendecke
7 */
9 #include <linux/sched.h>
10 #include <linux/kernel.h>
11 #include <linux/errno.h>
12 #include <linux/fcntl.h>
13 #include <linux/stat.h>
14 #include <linux/mm.h>
15 #include <linux/malloc.h>
16 #include <linux/pagemap.h>
18 #include <asm/uaccess.h>
19 #include <asm/system.h>
21 #include <linux/smbno.h>
22 #include <linux/smb_fs.h>
24 #define SMBFS_PARANOIA 1
25 /* #define SMBFS_DEBUG_VERBOSE 1 */
26 /* #define pr_debug printk */
28 static inline int
29 min(int a, int b)
31 return a < b ? a : b;
34 static inline void
35 smb_unlock_page(struct page *page)
37 clear_bit(PG_locked, &page->flags);
38 wake_up(&page->wait);
41 static int
42 smb_fsync(struct file *file, struct dentry * dentry)
44 #ifdef SMBFS_DEBUG_VERBOSE
45 printk("smb_fsync: sync file %s/%s\n",
46 dentry->d_parent->d_name.name, dentry->d_name.name);
47 #endif
48 return 0;
52 * Read a page synchronously.
54 static int
55 smb_readpage_sync(struct dentry *dentry, struct page *page)
57 char *buffer = (char *) page_address(page);
58 unsigned long offset = page->offset;
59 int rsize = smb_get_rsize(server_from_dentry(dentry));
60 int count = PAGE_SIZE;
61 int result;
63 clear_bit(PG_error, &page->flags);
65 #ifdef SMBFS_DEBUG_VERBOSE
66 printk("smb_readpage_sync: file %s/%s, count=%d@%ld, rsize=%d\n",
67 dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, rsize);
68 #endif
69 result = smb_open(dentry, SMB_O_RDONLY);
70 if (result < 0)
72 #ifdef SMBFS_PARANOIA
73 printk("smb_readpage_sync: %s/%s open failed, error=%d\n",
74 dentry->d_parent->d_name.name, dentry->d_name.name, result);
75 #endif
76 goto io_error;
79 do {
80 if (count < rsize)
81 rsize = count;
83 result = smb_proc_read(dentry, offset, rsize, buffer);
84 if (result < 0)
85 goto io_error;
87 count -= result;
88 offset += result;
89 buffer += result;
90 dentry->d_inode->i_atime = CURRENT_TIME;
91 if (result < rsize)
92 break;
93 } while (count);
95 memset(buffer, 0, count);
96 set_bit(PG_uptodate, &page->flags);
97 result = 0;
99 io_error:
100 smb_unlock_page(page);
101 return result;
105 smb_readpage(struct file *file, struct page *page)
107 struct dentry *dentry = file->f_dentry;
108 int error;
110 pr_debug("SMB: smb_readpage %08lx\n", page_address(page));
111 #ifdef SMBFS_PARANOIA
112 if (test_bit(PG_locked, &page->flags))
113 printk("smb_readpage: page already locked!\n");
114 #endif
115 set_bit(PG_locked, &page->flags);
116 atomic_inc(&page->count);
117 error = smb_readpage_sync(dentry, page);
118 free_page(page_address(page));
119 return error;
123 * Write a page synchronously.
124 * Offset is the data offset within the page.
126 static int
127 smb_writepage_sync(struct dentry *dentry, struct page *page,
128 unsigned long offset, unsigned int count)
130 struct inode *inode = dentry->d_inode;
131 u8 *buffer = (u8 *) page_address(page) + offset;
132 int wsize = smb_get_wsize(server_from_dentry(dentry));
133 int result, written = 0;
135 offset += page->offset;
136 #ifdef SMBFS_DEBUG_VERBOSE
137 printk("smb_writepage_sync: file %s/%s, count=%d@%ld, wsize=%d\n",
138 dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, wsize);
139 #endif
141 do {
142 if (count < wsize)
143 wsize = count;
145 result = smb_proc_write(dentry, offset, wsize, buffer);
146 if (result < 0)
147 goto io_error;
148 /* N.B. what if result < wsize?? */
149 #ifdef SMBFS_PARANOIA
150 if (result < wsize)
151 printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
152 #endif
153 buffer += wsize;
154 offset += wsize;
155 written += wsize;
156 count -= wsize;
158 * Update the inode now rather than waiting for a refresh.
160 inode->i_mtime = inode->i_atime = CURRENT_TIME;
161 if (offset > inode->i_size)
162 inode->i_size = offset;
163 inode->u.smbfs_i.cache_valid |= SMB_F_LOCALWRITE;
164 } while (count);
166 out:
167 smb_unlock_page(page);
168 return written ? written : result;
170 io_error:
171 /* Must mark the page invalid after I/O error */
172 clear_bit(PG_uptodate, &page->flags);
173 goto out;
177 * Write a page to the server. This will be used for NFS swapping only
178 * (for now), and we currently do this synchronously only.
180 static int
181 smb_writepage(struct file *file, struct page *page)
183 struct dentry *dentry = file->f_dentry;
184 int result;
186 #ifdef SMBFS_PARANOIA
187 if (test_bit(PG_locked, &page->flags))
188 printk("smb_writepage: page already locked!\n");
189 #endif
190 set_bit(PG_locked, &page->flags);
191 atomic_inc(&page->count);
192 result = smb_writepage_sync(dentry, page, 0, PAGE_SIZE);
193 free_page(page_address(page));
194 return result;
197 static int
198 smb_updatepage(struct file *file, struct page *page, unsigned long offset, unsigned int count, int sync)
200 struct dentry *dentry = file->f_dentry;
202 pr_debug("SMBFS: smb_updatepage(%s/%s %d@%ld, sync=%d)\n",
203 dentry->d_parent->d_name.name, dentry->d_name.name,
204 count, page->offset+offset, sync);
206 return smb_writepage_sync(dentry, page, offset, count);
209 static ssize_t
210 smb_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
212 struct dentry * dentry = file->f_dentry;
213 ssize_t status;
215 #ifdef SMBFS_DEBUG_VERBOSE
216 printk("smb_file_read: file %s/%s, count=%lu@%lu\n",
217 dentry->d_parent->d_name.name, dentry->d_name.name,
218 (unsigned long) count, (unsigned long) *ppos);
219 #endif
221 status = smb_revalidate_inode(dentry);
222 if (status)
224 #ifdef SMBFS_PARANOIA
225 printk("smb_file_read: %s/%s validation failed, error=%d\n",
226 dentry->d_parent->d_name.name, dentry->d_name.name, status);
227 #endif
228 goto out;
231 #ifdef SMBFS_DEBUG_VERBOSE
232 printk("smb_file_read: before read, size=%ld, pages=%ld, flags=%x, atime=%ld\n",
233 dentry->d_inode->i_size, dentry->d_inode->i_nrpages, dentry->d_inode->i_flags,
234 dentry->d_inode->i_atime);
235 #endif
236 status = generic_file_read(file, buf, count, ppos);
237 out:
238 return status;
241 static int
242 smb_file_mmap(struct file * file, struct vm_area_struct * vma)
244 struct dentry * dentry = file->f_dentry;
245 int status;
247 #ifdef SMBFS_DEBUG_VERBOSE
248 printk("smb_file_mmap: file %s/%s, address %lu - %lu\n",
249 dentry->d_parent->d_name.name, dentry->d_name.name, vma->vm_start, vma->vm_end);
250 #endif
252 status = smb_revalidate_inode(dentry);
253 if (status)
255 #ifdef SMBFS_PARANOIA
256 printk("smb_file_mmap: %s/%s validation failed, error=%d\n",
257 dentry->d_parent->d_name.name, dentry->d_name.name, status);
258 #endif
259 goto out;
261 status = generic_file_mmap(file, vma);
262 out:
263 return status;
267 * Write to a file (through the page cache).
269 static ssize_t
270 smb_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
272 struct dentry * dentry = file->f_dentry;
273 ssize_t result;
275 #ifdef SMBFS_DEBUG_VERBOSE
276 printk("smb_file_write: file %s/%s, count=%lu@%lu, pages=%ld\n",
277 dentry->d_parent->d_name.name, dentry->d_name.name,
278 (unsigned long) count, (unsigned long) *ppos, dentry->d_inode->i_nrpages);
279 #endif
281 result = smb_revalidate_inode(dentry);
282 if (result)
284 #ifdef SMBFS_PARANOIA
285 printk("smb_file_write: %s/%s validation failed, error=%d\n",
286 dentry->d_parent->d_name.name, dentry->d_name.name, result);
287 #endif
288 goto out;
291 result = smb_open(dentry, SMB_O_WRONLY);
292 if (result)
293 goto out;
295 if (count > 0)
297 result = generic_file_write(file, buf, count, ppos);
298 #ifdef SMBFS_DEBUG_VERBOSE
299 printk("smb_file_write: pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
300 (long) file->f_pos, dentry->d_inode->i_size, dentry->d_inode->i_mtime,
301 dentry->d_inode->i_atime);
302 #endif
304 out:
305 return result;
308 static int
309 smb_file_open(struct inode *inode, struct file * file)
311 #ifdef SMBFS_DEBUG_VERBOSE
312 printk("smb_file_open: opening %s/%s, d_count=%d\n",
313 file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
314 file->f_dentry->d_count);
315 #endif
316 return 0;
319 static int
320 smb_file_release(struct inode *inode, struct file * file)
322 struct dentry * dentry = file->f_dentry;
324 #ifdef SMBFS_DEBUG_VERBOSE
325 printk("smb_file_release: closing %s/%s, d_count=%d\n",
326 dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
327 #endif
329 if (dentry->d_count == 1)
331 smb_close(inode);
333 return 0;
337 * Check whether the required access is compatible with
338 * an inode's permission. SMB doesn't recognize superuser
339 * privileges, so we need our own check for this.
341 static int
342 smb_file_permission(struct inode *inode, int mask)
344 int mode = inode->i_mode;
345 int error = 0;
347 #ifdef SMBFS_DEBUG_VERBOSE
348 printk("smb_file_permission: mode=%x, mask=%x\n", mode, mask);
349 #endif
350 /* Look at user permissions */
351 mode >>= 6;
352 if ((mode & 7 & mask) != mask)
353 error = -EACCES;
354 return error;
357 static struct file_operations smb_file_operations =
359 NULL, /* lseek - default */
360 smb_file_read, /* read */
361 smb_file_write, /* write */
362 NULL, /* readdir - bad */
363 NULL, /* poll - default */
364 smb_ioctl, /* ioctl */
365 smb_file_mmap, /* mmap(struct file*, struct vm_area_struct*) */
366 smb_file_open, /* open(struct inode*, struct file*) */
367 NULL, /* flush */
368 smb_file_release, /* release(struct inode*, struct file*) */
369 smb_fsync, /* fsync(struct file*, struct dentry*) */
370 NULL, /* fasync(struct file*, int) */
371 NULL, /* check_media_change(kdev_t dev) */
372 NULL, /* revalidate(kdev_t dev) */
373 NULL /* lock(struct file*, int, struct file_lock*) */
376 struct inode_operations smb_file_inode_operations =
378 &smb_file_operations, /* default file operations */
379 NULL, /* create */
380 NULL, /* lookup */
381 NULL, /* link */
382 NULL, /* unlink */
383 NULL, /* symlink */
384 NULL, /* mkdir */
385 NULL, /* rmdir */
386 NULL, /* mknod */
387 NULL, /* rename */
388 NULL, /* readlink */
389 NULL, /* follow_link */
390 smb_readpage, /* readpage */
391 smb_writepage, /* writepage */
392 NULL, /* bmap */
393 NULL, /* truncate */
394 smb_file_permission, /* permission */
395 NULL, /* smap */
396 smb_updatepage, /* updatepage */
397 smb_revalidate_inode, /* revalidate */