Whamcloud - gitweb
- added comment in mds_open() and GNS mount points.
[fs/lustre-release.git] / lustre / llite / special.c
index 6efa32b..33401fc 100644 (file)
@@ -1,9 +1,10 @@
 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  * vim:expandtab:shiftwidth=8:tabstop=8:
  *
+ * Special file handling for Lustre.
+ *
  *  Copyright (c) 2002, 2003 Cluster File Systems, Inc.
- *   Author: Peter Braam <braam@clusterfs.com>
- *   Author: Phil Schwan <phil@clusterfs.com>
+ *   Author: Wang Di <wangdi@clusterfs.com>
  *   Author: Andreas Dilger <adilger@clusterfs.com>
  *
  *   This file is part of Lustre, http://www.lustre.org.
  */
 
 #define DEBUG_SUBSYSTEM S_LLITE
+#include <linux/lustre_dlm.h>
 #include <linux/lustre_lite.h>
+#include <linux/pagemap.h>
 #include <linux/file.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include <linux/lustre_compat25.h>
+#endif
 #include <asm/poll.h>
 #include "llite_internal.h"
 
-#define FILE_OPS 0 
-#define INODE_OPS 1 
+#define INODE_OPS 1
+#define FILE_OPS 2
 
-static inline struct file_operations** 
-get_save_fops(struct file* filp, int mode)
+static struct file_operations **get_save_fops(struct file* filp, int mode)
 {
         struct inode *inode = filp->f_dentry->d_inode;
         struct ll_inode_info *lli = ll_i2info(inode);
-        if (mode == FILE_OPS){
-                if (S_ISFIFO(inode->i_mode)){
+
+        if (mode == INODE_OPS) {
+                return &(lli->ll_save_ifop);
+        } else if (mode == FILE_OPS) {
+                if (S_ISFIFO(inode->i_mode)) {
                         switch (filp->f_mode) {
                         case 1: /*O_RDONLY*/
                                 return &(lli->ll_save_ffop);
@@ -50,62 +58,64 @@ get_save_fops(struct file* filp, int mode)
                         }
                 }
                 return &(lli->ll_save_ffop);
-        } else
-                return &(lli->ll_save_ifop);
-
+        } else {
+                CERROR("invalid special file ops %d\n", mode);
+                LBUG();
+                return NULL;
+        }
 }
-                                          
 
-static inline void save_fops(struct file *filp, struct inode *inode,
-                             struct file_operations *sfops) 
+static void save_fops(struct file *filp, struct inode *inode,
+                      struct file_operations *sfops)
 {
         if (sfops != filp->f_op) {
-                struct file_operations** pfop = get_save_fops (filp, FILE_OPS);
-                struct module   *save_module = NULL;
+                struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
 
-                save_module = filp->f_op->owner;
                 *pfop = filp->f_op;
-                if (S_ISCHR(inode->i_mode)) {
+                if (S_ISCHR(inode->i_mode))
                         filp->f_op = &ll_special_chr_file_fops;
-                }else if (S_ISFIFO(inode->i_mode)){
+                else if (S_ISFIFO(inode->i_mode))
                         filp->f_op = &ll_special_fifo_file_fops;
-                }
-                filp->f_op->owner = save_module;
+
+                CDEBUG(D_INFO,"saved %p, replaced with %p\n", *pfop,filp->f_op);
+                if ((*pfop)->owner)
+                        CDEBUG(D_INFO,"%p has owner %p\n",*pfop,(*pfop)->owner);
         }
 }
 
-static ssize_t ll_special_file_read(struct file *filp, char *buf, 
+static ssize_t ll_special_file_read(struct file *filp, char *buf,
                                     size_t count, loff_t *ppos)
 {
-        struct file_operations** pfop = get_save_fops (filp, FILE_OPS);
-        int    rc = -EINVAL;
+        struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+        int rc = -EINVAL;
 
-        if (pfop && *pfop && (*pfop)->read) 
+        if (pfop && *pfop && (*pfop)->read)
                 rc = (*pfop)->read(filp, buf, count, ppos);
-        
+
         RETURN(rc);
 }
 
-static ssize_t ll_special_file_write(struct file *filp, const char *buf, 
+static ssize_t ll_special_file_write(struct file *filp, const char *buf,
                                      size_t count, loff_t *ppos)
 {
-        struct file_operations** pfop = get_save_fops (filp, FILE_OPS);
-        int    rc = -EINVAL;
-        
-        if (pfop && *pfop && (*pfop)->write) 
+        struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+        int rc = -EINVAL;
+
+        if (pfop && *pfop && (*pfop)->write)
                 rc = (*pfop)->write(filp, buf, count, ppos);
-        
+
         RETURN(rc);
 }
-static int ll_special_file_ioctl(struct inode *inode, struct file *filp, 
+
+static int ll_special_file_ioctl(struct inode *inode, struct file *filp,
                                  unsigned int cmd, unsigned long arg)
 {
-        struct file_operations** pfop = get_save_fops (filp, FILE_OPS);
-        int    rc = -ENOTTY;
+        struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+        int rc = -ENOTTY;
 
-        if (pfop && *pfop && (*pfop)->ioctl) { 
+        if (pfop && *pfop && (*pfop)->ioctl) {
                 struct file_operations *sfops = filp->f_op;
-                
+
                 rc = (*pfop)->ioctl(inode, filp, cmd, arg);
                 save_fops(filp, inode, sfops);
         }
@@ -114,27 +124,27 @@ static int ll_special_file_ioctl(struct inode *inode, struct file *filp,
 
 static loff_t ll_special_file_seek(struct file *filp, loff_t offset, int origin)
 {
-        struct file_operations** pfop = get_save_fops (filp, FILE_OPS);
-        int    rc = 0;
+        struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+        int rc = 0;
 
-        if (pfop && *pfop && (*pfop)->llseek)  
+        if (pfop && *pfop && (*pfop)->llseek)
                 rc = (*pfop)->llseek(filp, offset, origin);
         else
                 rc = default_llseek(filp, offset, origin);
-       
+
         RETURN(rc);
 }
 
 
 #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
 
-static unsigned int
-ll_special_file_poll(struct file *filp, struct poll_table_struct *poll_table) 
+static unsigned int ll_special_file_poll(struct file *filp,
+                                         struct poll_table_struct *poll_table)
 {
-        struct file_operations** pfop = get_save_fops (filp, FILE_OPS);
-        int    rc = DEFAULT_POLLMASK;
+        struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+        int rc = DEFAULT_POLLMASK;
 
-        if (pfop && *pfop && (*pfop)->poll)  
+        if (pfop && *pfop && (*pfop)->poll)
                 rc = (*pfop)->poll(filp, poll_table);
 
         RETURN(rc);
@@ -142,49 +152,57 @@ ll_special_file_poll(struct file *filp, struct poll_table_struct *poll_table)
 
 static int ll_special_file_open(struct inode *inode, struct file *filp)
 {
-        struct file_operations** pfop = get_save_fops (filp, FILE_OPS);
+        struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
         int rc = -EINVAL;
 
-        if (pfop && *pfop && (*pfop)->open)  
-                rc = (*pfop)->open(inode, filp);
-        
+        if (pfop && *pfop) {
+                fops_get(*pfop);
+
+                if ((*pfop)->open)
+                        rc = (*pfop)->open(inode, filp);
+
+                if (rc)
+                        fops_put(*pfop);
+        }
+
         RETURN(rc);
 }
 
-static ssize_t ll_special_read(struct file *filp, char *buf, 
-                               size_t count, loff_t *ppos)
+static ssize_t ll_special_read(struct file *filp, char *buf, size_t count,
+                               loff_t *ppos)
 {
-        struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
-        int    rc = -EINVAL;
+        struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+        int rc = -EINVAL;
 
-        if (pfop && *pfop && (*pfop)->read)  
+        if (pfop && *pfop && (*pfop)->read)
                 rc = (*pfop)->read(filp, buf, count, ppos);
-        
+
         RETURN(rc);
 }
 
-static ssize_t ll_special_write(struct file *filp, const char *buf, 
+static ssize_t ll_special_write(struct file *filp, const char *buf,
                                 size_t count, loff_t *ppos)
 {
-        struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
-        int    rc = -EINVAL;
+        struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+        int rc = -EINVAL;
 
-        if (pfop && *pfop && (*pfop)->write)  
+        if (pfop && *pfop && (*pfop)->write)
                 rc = (*pfop)->write(filp, buf, count, ppos);
-        
+
         RETURN(rc);
 }
 
-static int ll_special_ioctl(struct inode *inode, struct file *filp, 
+static int ll_special_ioctl(struct inode *inode, struct file *filp,
                             unsigned int cmd, unsigned long arg)
 {
-        struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
-        int    rc = -ENOTTY;
+        struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+        int rc = -ENOTTY;
 
-        if (pfop && *pfop && (*pfop)->ioctl) { 
+        if (pfop && *pfop && (*pfop)->ioctl) {
                 struct file_operations *sfops = filp->f_op;
-                
+                       
                 rc = (*pfop)->ioctl(inode, filp, cmd, arg);
+
                 /* sometimes, file_operations will be changed in ioctl */
                 save_fops(filp, inode, sfops);
         }
@@ -194,12 +212,12 @@ static int ll_special_ioctl(struct inode *inode, struct file *filp,
 
 static int ll_special_mmap(struct file * filp, struct vm_area_struct * vma)
 {
-        struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
-        int    rc = -ENODEV;
+        struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+        int rc = -ENODEV;
 
-        if (pfop && *pfop && (*pfop)->mmap)  
+        if (pfop && *pfop && (*pfop)->mmap)
                 rc = (*pfop)->mmap(filp, vma);
-        
+
         RETURN(rc);
 }
 
@@ -208,20 +226,20 @@ static loff_t ll_special_seek(struct file *filp, loff_t offset, int origin)
         struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
         int    rc = 0;
 
-        if (pfop && *pfop && (*pfop)->llseek)  
+        if (pfop && *pfop && (*pfop)->llseek)
                 rc = (*pfop)->llseek(filp, offset, origin);
         else
                 rc = default_llseek(filp, offset, origin);
-       
+
         RETURN(rc);
 }
 
 static int ll_special_fsync(struct file *filp, struct dentry *dentry, int data)
 {
-        struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
-        int    rc = -EINVAL;
+        struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+        int rc = -EINVAL;
 
-        if (pfop && *pfop && (*pfop)->fsync)  
+        if (pfop && *pfop && (*pfop)->fsync)
                 rc = (*pfop)->fsync(filp, dentry, data);
 
         RETURN(rc);
@@ -229,137 +247,212 @@ static int ll_special_fsync(struct file *filp, struct dentry *dentry, int data)
 
 static int ll_special_file_fasync(int fd, struct file *filp, int on)
 {
-        struct file_operations** pfop = get_save_fops (filp, FILE_OPS);
-        int    rc = -EINVAL;
+        struct file_operations **pfop = get_save_fops(filp, FILE_OPS);
+        int rc = -EINVAL;
 
-        if (pfop && *pfop && (*pfop)->fasync)  
+        if (pfop && *pfop && (*pfop)->fasync)
                 rc = (*pfop)->fasync(fd, filp, on);
 
         RETURN(rc);
 }
 
+static int ll_special_release_internal(struct inode *inode, struct file *filp,
+                                       int mode)
+{
+       struct file_operations **pfop = get_save_fops(filp, mode);
+       struct ll_sb_info *sbi = ll_i2sbi(inode);
+       int rc = 0, err;
+       ENTRY;
+
+        if (pfop && *pfop) {
+                if ((*pfop)->release)
+                        rc = (*pfop)->release(inode, filp);
+                fops_put(*pfop);
+        }
+
+        lprocfs_counter_incr(sbi->ll_stats, LPROC_LL_RELEASE);
+        err = ll_md_close(sbi->ll_md_exp, inode, filp);
+
+        if (err && rc == 0)
+                rc = err;
+
+        RETURN(rc);
+}
+
 static int ll_special_open(struct inode *inode, struct file *filp)
 {
+        struct file_operations **pfop = get_save_fops(filp, INODE_OPS);
+        struct file_operations *sfops = filp->f_op;
+        struct ll_inode_info *lli = ll_i2info(inode);
         struct ptlrpc_request *req;
-        struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
         struct lookup_intent *it;
-        int rc = -EINVAL;
+        int rc = -EINVAL, err;
+        struct obd_client_handle **och_p;
+        __u64 *och_usecount;
         ENTRY;
-        
-        if (pfop && *pfop && (*pfop)->open) { 
-                struct file_operations *sfops = filp->f_op;
-                
-                rc = (*pfop)->open(inode, filp);
-                 /* sometimes the file_operations will be changed in open */
-                save_fops(filp, inode, sfops);
+
+        it = filp->f_it;
+
+        if (LUSTRE_IT(it)->it_disposition) {
+                err = it_open_error(DISP_OPEN_OPEN, it);
+                if (err)
+                        RETURN(err);
         }
-        
+
+        if (pfop && *pfop) {
+                /* mostly we will have @def_blk_fops here and it is not in a
+                 * module but we do this just to be sure. */
+                fops_get(*pfop);
+
+                if ((*pfop)->open) {
+                        rc = (*pfop)->open(inode, filp);
+
+                        if (rc)
+                                fops_put(*pfop);
+                        else    /* sometimes ops will be changed in open */
+                                save_fops(filp, inode, sfops);
+                }
+        }
+
+        /* Let's see if we have file open on MDS already. */
+        if (it->it_flags & FMODE_WRITE) {
+                och_p = &lli->lli_mds_write_och;
+                och_usecount = &lli->lli_open_fd_write_count;
+        } else if (it->it_flags & FMODE_EXEC) {
+                och_p = &lli->lli_mds_exec_och;
+                och_usecount = &lli->lli_open_fd_exec_count;
+         } else {
+                och_p = &lli->lli_mds_read_och;
+                och_usecount = &lli->lli_open_fd_read_count;
+        }
+
         lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_OPEN);
-        
-        it = filp->f_it;
-        
-        rc = ll_local_open(filp, it);
-        if (rc)
-                RETURN(rc);
-        req = it->d.lustre.it_data;
+
+        down(&lli->lli_och_sem);
+        if (*och_p) { /* Open handle is present */
+                if (LUSTRE_IT(it)->it_disposition) {
+                        struct obd_client_handle *och;
+                        /* Well, there's extra open request that we do not need,
+                           let's close it somehow*/
+                        OBD_ALLOC(och, sizeof (struct obd_client_handle));
+                        if (!och) {
+                                /* XXX We leak open fd and open OPEN connectioni
+                                   to server here */
+                                up(&lli->lli_och_sem);
+                                RETURN(-ENOMEM);
+                        }
+                        ll_och_fill(inode, it, och);
+                        /* ll_md_och_close() will free och */
+                        ll_md_och_close(ll_i2mdexp(inode), inode, och);
+                }       
+                (*och_usecount)++;        
+
+                err = ll_local_open(filp, it, NULL);
+        } else {
+                LASSERT(*och_usecount == 0);
+                OBD_ALLOC(*och_p, sizeof (struct obd_client_handle));
+                if (!*och_p) {
+                        // XXX Same as above
+                        up(&lli->lli_och_sem);
+                        RETURN(-ENOMEM);
+                }
+                (*och_usecount)++;
+
+                err = ll_local_open(filp, it, *och_p);
+        }
+        up(&lli->lli_och_sem);
+
+        if (rc != 0) {
+                CERROR("error opening special file: rc %d\n", rc);
+                ll_md_close(ll_i2sbi(inode)->ll_md_exp, inode, filp);
+        } else if (err) {
+                if (pfop && *pfop) {
+                        if ((*pfop)->release)
+                                (*pfop)->release(inode, filp);
+                        fops_put(*pfop);
+                }
+                rc = err;
+        }
+
+        req = LUSTRE_IT(it)->it_data;
         if (req)
                 ptlrpc_req_finished(req);
-        
+
         RETURN(rc);
 }
 
 static int ll_special_release(struct inode *inode, struct file *filp)
 {
-       struct ll_sb_info *sbi = ll_i2sbi(inode);
-       struct file_operations** pfop = get_save_fops (filp, INODE_OPS);
-       int rc = 0, rc2 = 0;
-       ENTRY;
-
-        if (pfop && *pfop && (*pfop)->release) { 
-                rc = (*pfop)->release(inode, filp);
-        }
-        lprocfs_counter_incr(sbi->ll_stats, LPROC_LL_RELEASE);
-                
-        rc2 = ll_mdc_close(sbi->ll_mdc_exp, inode, filp);
-                
-        if (rc2 && !rc)
-                rc = rc2;
-        
-        RETURN(rc);
+        return ll_special_release_internal(inode, filp, INODE_OPS);
 }
 
 static int ll_special_file_release(struct inode *inode, struct file *filp)
 {
-        struct ll_sb_info *sbi = ll_i2sbi(inode);
-        struct file_operations** pfop = get_save_fops (filp, FILE_OPS);
-        int rc = 0, rc2 = 0;
-        ENTRY;
-
-        if (pfop && *pfop && (*pfop)->release) { 
-                rc = (*pfop)->release(inode, filp);
-        }
-        lprocfs_counter_incr(sbi->ll_stats, LPROC_LL_RELEASE);
-                
-        rc2 = ll_mdc_close(sbi->ll_mdc_exp, inode, filp);
-                
-        if (rc2 && !rc)
-               rc = rc2;
-
-        RETURN(rc);
-
+        return ll_special_release_internal(inode, filp, FILE_OPS);
 }
 
 struct inode_operations ll_special_inode_operations = {
-        setattr_raw:    ll_setattr_raw,
-        setattr:        ll_setattr,
+        .setattr        = ll_setattr,
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-        getattr_it:     ll_getattr,
+        .getattr        = ll_getattr,
 #else
-        revalidate_it:  ll_inode_revalidate_it,
+        .revalidate_it  = ll_inode_revalidate_it,
 #endif
+        .setxattr       = ll_setxattr,
+        .getxattr       = ll_getxattr,
+        .listxattr      = ll_listxattr,
+        .removexattr    = ll_removexattr,
+        .permission     = ll_inode_permission,
+        
 };
 
 struct file_operations ll_special_chr_inode_fops = {
-       open:           ll_special_open,
+        //FIXME .owner          = THIS_MODULE,
+        .open           = ll_special_open,
 };
 
 struct file_operations ll_special_blk_inode_fops = {
-        read:           ll_special_read,
-        write:          ll_special_write,
-        ioctl:          ll_special_ioctl,
-        open:           ll_special_open,
-        release:        ll_special_release,
-        mmap:           ll_special_mmap,
-        llseek:         ll_special_seek,
-        fsync:          ll_special_fsync,
+        //FIXME .owner          = THIS_MODULE,
+        .read           = ll_special_read,
+        .write          = ll_special_write,
+        .ioctl          = ll_special_ioctl,
+        .open           = ll_special_open,
+        .release        = ll_special_release,
+        .mmap           = ll_special_mmap,
+        .llseek         = ll_special_seek,
+        .fsync          = ll_special_fsync,
 };
 
 struct file_operations ll_special_fifo_inode_fops = {
-        open:           ll_special_open,      
+        //FIXME .owner          = THIS_MODULE,
+        .open           = ll_special_open,
 };
 
 struct file_operations ll_special_sock_inode_fops = {
-        open:           ll_special_open
+        //FIXME .owner          = THIS_MODULE,
+        .open           = ll_special_open
 };
 
 struct file_operations ll_special_chr_file_fops = {
-       llseek:         ll_special_file_seek,
-       read:           ll_special_file_read,
-       write:          ll_special_file_write,
-       poll:           ll_special_file_poll,
-       ioctl:          ll_special_file_ioctl,
-       open:           ll_special_file_open,
-       release:        ll_special_file_release,
-       fasync:         ll_special_file_fasync,
+        //FIXME .owner          = THIS_MODULE,
+        .llseek         = ll_special_file_seek,
+        .read           = ll_special_file_read,
+        .write          = ll_special_file_write,
+        .poll           = ll_special_file_poll,
+        .ioctl          = ll_special_file_ioctl,
+        .open           = ll_special_file_open,
+        .release        = ll_special_file_release,
+        .fasync         = ll_special_file_fasync,
 };
 
 struct file_operations ll_special_fifo_file_fops = {
-       llseek:         ll_special_file_seek,
-       read:           ll_special_file_read,
-       write:          ll_special_file_write,
-       poll:           ll_special_file_poll,
-       ioctl:          ll_special_file_ioctl,
-       open:           ll_special_file_open,
-       release:        ll_special_file_release,
+        //FIXME .owner          = THIS_MODULE,
+        .llseek         = ll_special_file_seek,
+        .read           = ll_special_file_read,
+        .write          = ll_special_file_write,
+        .poll           = ll_special_file_poll,
+        .ioctl          = ll_special_file_ioctl,
+        .open           = ll_special_file_open,
+        .release        = ll_special_file_release,
 };