The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/smbfs/file.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  file.c
    3  *
    4  *  Copyright (C) 1995, 1996, 1997 by Paal-Kr. Engstad and Volker Lendecke
    5  *  Copyright (C) 1997 by Volker Lendecke
    6  *
    7  *  Please add a note about your changes to smbfs in the ChangeLog file.
    8  */
    9 
   10 #include <linux/sched.h>
   11 #include <linux/kernel.h>
   12 #include <linux/errno.h>
   13 #include <linux/fcntl.h>
   14 #include <linux/stat.h>
   15 #include <linux/mm.h>
   16 #include <linux/slab.h>
   17 #include <linux/pagemap.h>
   18 #include <linux/smp_lock.h>
   19 
   20 #include <asm/uaccess.h>
   21 #include <asm/system.h>
   22 
   23 #include <linux/smbno.h>
   24 #include <linux/smb_fs.h>
   25 
   26 #include "smb_debug.h"
   27 #include "proto.h"
   28 
   29 static int
   30 smb_fsync(struct file *file, struct dentry * dentry, int datasync)
   31 {
   32         struct smb_sb_info *server = server_from_dentry(dentry);
   33         int result;
   34 
   35         VERBOSE("sync file %s/%s\n", DENTRY_PATH(dentry));
   36 
   37         /*
   38          * The VFS will writepage() all dirty pages for us, but we
   39          * should send a SMBflush to the server, letting it know that
   40          * we want things synchronized with actual storage.
   41          *
   42          * Note: this function requires all pages to have been written already
   43          *       (should be ok with writepage_sync)
   44          */
   45         smb_lock_server(server);
   46         result = smb_proc_flush(server, dentry->d_inode->u.smbfs_i.fileid);
   47         smb_unlock_server(server);
   48         return result;
   49 }
   50 
   51 /*
   52  * Read a page synchronously.
   53  */
   54 static int
   55 smb_readpage_sync(struct dentry *dentry, struct page *page)
   56 {
   57         char *buffer = kmap(page);
   58         unsigned long offset = page->index << PAGE_CACHE_SHIFT;
   59         int rsize = smb_get_rsize(server_from_dentry(dentry));
   60         int count = PAGE_SIZE;
   61         int result;
   62 
   63         VERBOSE("file %s/%s, count=%d@%ld, rsize=%d\n",
   64                 DENTRY_PATH(dentry), count, offset, rsize);
   65 
   66         result = smb_open(dentry, SMB_O_RDONLY);
   67         if (result < 0) {
   68                 PARANOIA("%s/%s open failed, error=%d\n",
   69                          DENTRY_PATH(dentry), result);
   70                 goto io_error;
   71         }
   72 
   73         do {
   74                 if (count < rsize)
   75                         rsize = count;
   76 
   77                 result = smb_proc_read(dentry->d_inode, offset, rsize, buffer);
   78                 if (result < 0)
   79                         goto io_error;
   80 
   81                 count -= result;
   82                 offset += result;
   83                 buffer += result;
   84                 dentry->d_inode->i_atime = CURRENT_TIME;
   85                 if (result < rsize)
   86                         break;
   87         } while (count);
   88 
   89         memset(buffer, 0, count);
   90         flush_dcache_page(page);
   91         SetPageUptodate(page);
   92         result = 0;
   93 
   94 io_error:
   95         kunmap(page);
   96         UnlockPage(page);
   97         return result;
   98 }
   99 
  100 /*
  101  * We are called with the page locked and we unlock it when done.
  102  */
  103 static int
  104 smb_readpage(struct file *file, struct page *page)
  105 {
  106         int             error;
  107         struct dentry  *dentry = file->f_dentry;
  108 
  109         get_page(page);
  110         error = smb_readpage_sync(dentry, page);
  111         put_page(page);
  112         return error;
  113 }
  114 
  115 /*
  116  * Write a page synchronously.
  117  * Offset is the data offset within the page.
  118  */
  119 static int
  120 smb_writepage_sync(struct inode *inode, struct page *page,
  121                    unsigned long offset, unsigned int count)
  122 {
  123         char *buffer = kmap(page) + offset;
  124         int wsize = smb_get_wsize(server_from_inode(inode));
  125         int result, written = 0;
  126 
  127         offset += page->index << PAGE_CACHE_SHIFT;
  128         VERBOSE("file ino=%ld, fileid=%d, count=%d@%ld, wsize=%d\n",
  129                 inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);
  130 
  131         do {
  132                 if (count < wsize)
  133                         wsize = count;
  134 
  135                 result = smb_proc_write(inode, offset, wsize, buffer);
  136                 if (result < 0) {
  137                         PARANOIA("failed write, wsize=%d, result=%d\n",
  138                                  wsize, result);
  139                         break;
  140                 }
  141                 /* N.B. what if result < wsize?? */
  142 #ifdef SMBFS_PARANOIA
  143                 if (result < wsize)
  144                         PARANOIA("short write, wsize=%d, result=%d\n",
  145                                  wsize, result);
  146 #endif
  147                 buffer += wsize;
  148                 offset += wsize;
  149                 written += wsize;
  150                 count -= wsize;
  151                 /*
  152                  * Update the inode now rather than waiting for a refresh.
  153                  */
  154                 inode->i_mtime = inode->i_atime = CURRENT_TIME;
  155                 inode->u.smbfs_i.flags |= SMB_F_LOCALWRITE;
  156                 if (offset > inode->i_size)
  157                         inode->i_size = offset;
  158         } while (count);
  159 
  160         kunmap(page);
  161         return written ? written : result;
  162 }
  163 
  164 /*
  165  * Write a page to the server. This will be used for NFS swapping only
  166  * (for now), and we currently do this synchronously only.
  167  *
  168  * We are called with the page locked and we unlock it when done.
  169  */
  170 static int
  171 smb_writepage(struct page *page)
  172 {
  173         struct address_space *mapping = page->mapping;
  174         struct inode *inode;
  175         unsigned long end_index;
  176         unsigned offset = PAGE_CACHE_SIZE;
  177         int err;
  178 
  179         if (!mapping)
  180                 BUG();
  181         inode = mapping->host;
  182         if (!inode)
  183                 BUG();
  184 
  185         end_index = inode->i_size >> PAGE_CACHE_SHIFT;
  186 
  187         /* easy case */
  188         if (page->index < end_index)
  189                 goto do_it;
  190         /* things got complicated... */
  191         offset = inode->i_size & (PAGE_CACHE_SIZE-1);
  192         /* OK, are we completely out? */
  193         if (page->index >= end_index+1 || !offset)
  194                 return -EIO;
  195 do_it:
  196         get_page(page);
  197         err = smb_writepage_sync(inode, page, 0, offset);
  198         SetPageUptodate(page);
  199         UnlockPage(page);
  200         put_page(page);
  201         return err;
  202 }
  203 
  204 static int
  205 smb_updatepage(struct file *file, struct page *page, unsigned long offset,
  206                unsigned int count)
  207 {
  208         struct dentry *dentry = file->f_dentry;
  209 
  210         DEBUG1("(%s/%s %d@%ld)\n", DENTRY_PATH(dentry), 
  211                count, (page->index << PAGE_CACHE_SHIFT)+offset);
  212 
  213         return smb_writepage_sync(dentry->d_inode, page, offset, count);
  214 }
  215 
  216 static ssize_t
  217 smb_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
  218 {
  219         struct dentry * dentry = file->f_dentry;
  220         ssize_t status;
  221 
  222         VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
  223                 (unsigned long) count, (unsigned long) *ppos);
  224 
  225         status = smb_revalidate_inode(dentry);
  226         if (status) {
  227                 PARANOIA("%s/%s validation failed, error=%Zd\n",
  228                          DENTRY_PATH(dentry), status);
  229                 goto out;
  230         }
  231 
  232         VERBOSE("before read, size=%ld, flags=%x, atime=%ld\n",
  233                 (long)dentry->d_inode->i_size,
  234                 dentry->d_inode->i_flags, dentry->d_inode->i_atime);
  235 
  236         status = generic_file_read(file, buf, count, ppos);
  237 out:
  238         return status;
  239 }
  240 
  241 static int
  242 smb_file_mmap(struct file * file, struct vm_area_struct * vma)
  243 {
  244         struct dentry * dentry = file->f_dentry;
  245         int     status;
  246 
  247         VERBOSE("file %s/%s, address %lu - %lu\n",
  248                 DENTRY_PATH(dentry), vma->vm_start, vma->vm_end);
  249 
  250         status = smb_revalidate_inode(dentry);
  251         if (status) {
  252                 PARANOIA("%s/%s validation failed, error=%d\n",
  253                          DENTRY_PATH(dentry), status);
  254                 goto out;
  255         }
  256         status = generic_file_mmap(file, vma);
  257 out:
  258         return status;
  259 }
  260 
  261 /*
  262  * This does the "real" work of the write. The generic routine has
  263  * allocated the page, locked it, done all the page alignment stuff
  264  * calculations etc. Now we should just copy the data from user
  265  * space and write it back to the real medium..
  266  *
  267  * If the writer ends up delaying the write, the writer needs to
  268  * increment the page use counts until he is done with the page.
  269  */
  270 static int smb_prepare_write(struct file *file, struct page *page, 
  271                              unsigned offset, unsigned to)
  272 {
  273         return 0;
  274 }
  275 
  276 static int smb_commit_write(struct file *file, struct page *page,
  277                             unsigned offset, unsigned to)
  278 {
  279         int status;
  280 
  281         status = -EFAULT;
  282         lock_kernel();
  283         status = smb_updatepage(file, page, offset, to-offset);
  284         unlock_kernel();
  285         return status;
  286 }
  287 
  288 struct address_space_operations smb_file_aops = {
  289         readpage: smb_readpage,
  290         writepage: smb_writepage,
  291         prepare_write: smb_prepare_write,
  292         commit_write: smb_commit_write
  293 };
  294 
  295 /* 
  296  * Write to a file (through the page cache).
  297  */
  298 static ssize_t
  299 smb_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
  300 {
  301         struct dentry * dentry = file->f_dentry;
  302         ssize_t result;
  303 
  304         VERBOSE("file %s/%s, count=%lu@%lu\n",
  305                 DENTRY_PATH(dentry),
  306                 (unsigned long) count, (unsigned long) *ppos);
  307 
  308         result = smb_revalidate_inode(dentry);
  309         if (result) {
  310                 PARANOIA("%s/%s validation failed, error=%Zd\n",
  311                          DENTRY_PATH(dentry), result);
  312                 goto out;
  313         }
  314 
  315         result = smb_open(dentry, SMB_O_WRONLY);
  316         if (result)
  317                 goto out;
  318 
  319         if (count > 0) {
  320                 result = generic_file_write(file, buf, count, ppos);
  321                 VERBOSE("pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
  322                         (long) file->f_pos, (long) dentry->d_inode->i_size,
  323                         dentry->d_inode->i_mtime, dentry->d_inode->i_atime);
  324         }
  325 out:
  326         return result;
  327 }
  328 
  329 static int
  330 smb_file_open(struct inode *inode, struct file * file)
  331 {
  332         int result;
  333         struct dentry *dentry = file->f_dentry;
  334         int smb_mode = (file->f_mode & O_ACCMODE) - 1;
  335 
  336         lock_kernel();
  337         result = smb_open(dentry, smb_mode);
  338         if (result)
  339                 goto out;
  340         inode->u.smbfs_i.openers++;
  341 out:
  342         unlock_kernel();
  343         return 0;
  344 }
  345 
  346 static int
  347 smb_file_release(struct inode *inode, struct file * file)
  348 {
  349         lock_kernel();
  350         if (!--inode->u.smbfs_i.openers) {
  351                 /* We must flush any dirty pages now as we won't be able to
  352                    write anything after close. mmap can trigger this.
  353                    "openers" should perhaps include mmap'ers ... */
  354                 filemap_fdatasync(inode->i_mapping);
  355                 filemap_fdatawait(inode->i_mapping);
  356                 smb_close(inode);
  357         }
  358         unlock_kernel();
  359         return 0;
  360 }
  361 
  362 /*
  363  * Check whether the required access is compatible with
  364  * an inode's permission. SMB doesn't recognize superuser
  365  * privileges, so we need our own check for this.
  366  */
  367 static int
  368 smb_file_permission(struct inode *inode, int mask)
  369 {
  370         int mode = inode->i_mode;
  371         int error = 0;
  372 
  373         VERBOSE("mode=%x, mask=%x\n", mode, mask);
  374 
  375         /* Look at user permissions */
  376         mode >>= 6;
  377         if ((mode & 7 & mask) != mask)
  378                 error = -EACCES;
  379         return error;
  380 }
  381 
  382 struct file_operations smb_file_operations =
  383 {
  384         llseek:         generic_file_llseek,
  385         read:           smb_file_read,
  386         write:          smb_file_write,
  387         ioctl:          smb_ioctl,
  388         mmap:           smb_file_mmap,
  389         open:           smb_file_open,
  390         release:        smb_file_release,
  391         fsync:          smb_fsync,
  392 };
  393 
  394 struct inode_operations smb_file_inode_operations =
  395 {
  396         permission:     smb_file_permission,
  397         revalidate:     smb_revalidate_inode,
  398         setattr:        smb_notify_change,
  399 };

Cache object: 5b211dcfba72fa728dd98113ca7b46d3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.