vserver 1.9.3
[linux-2.6.git] / fs / nfsd / nfsctl.c
index 5014476..161afdc 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/uaccess.h>
 
 /*
- *     We have a single directory with 8 nodes in it.
+ *     We have a single directory with 9 nodes in it.
  */
 enum {
        NFSD_Root = 1,
@@ -50,6 +50,7 @@ enum {
        NFSD_List,
        NFSD_Fh,
        NFSD_Threads,
+       NFSD_Leasetime,
 };
 
 /*
@@ -64,6 +65,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size);
 static ssize_t write_getfs(struct file *file, char *buf, size_t size);
 static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
 static ssize_t write_threads(struct file *file, char *buf, size_t size);
+static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
 
 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
        [NFSD_Svc] = write_svc,
@@ -75,103 +77,34 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
        [NFSD_Getfs] = write_getfs,
        [NFSD_Fh] = write_filehandle,
        [NFSD_Threads] = write_threads,
+       [NFSD_Leasetime] = write_leasetime,
 };
 
-/* an argresp is stored in an allocated page and holds the 
- * size of the argument or response, along with its content
- */
-struct argresp {
-       ssize_t size;
-       char data[0];
-};
-
-/*
- * transaction based IO methods.
- * The file expects a single write which triggers the transaction, and then
- * possibly a read which collects the result - which is stored in a 
- * file-local buffer.
- */
-static ssize_t TA_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
+static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
 {
        ino_t ino =  file->f_dentry->d_inode->i_ino;
-       struct argresp *ar;
-       ssize_t rv = 0;
+       char *data;
+       ssize_t rv;
 
        if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino])
                return -EINVAL;
-       if (file->private_data) 
-               return -EINVAL; /* only one write allowed per open */
-       if (size > PAGE_SIZE - sizeof(struct argresp))
-               return -EFBIG;
 
-       ar = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!ar)
-               return -ENOMEM;
-       ar->size = 0;
-       down(&file->f_dentry->d_inode->i_sem);
-       if (file->private_data)
-               rv = -EINVAL;
-       else
-               file->private_data = ar;
-       up(&file->f_dentry->d_inode->i_sem);
-       if (rv) {
-               kfree(ar);
-               return rv;
-       }
-       if (copy_from_user(ar->data, buf, size))
-               return -EFAULT;
-       
-       rv =  write_op[ino](file, ar->data, size);
+       data = simple_transaction_get(file, buf, size);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       rv =  write_op[ino](file, data, size);
        if (rv>0) {
-               ar->size = rv;
+               simple_transaction_set(file, rv);
                rv = size;
        }
        return rv;
 }
 
-
-static ssize_t TA_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
-{
-       struct argresp *ar;
-       ssize_t rv = 0;
-       
-       if (file->private_data == NULL)
-               rv = TA_write(file, buf, 0, pos);
-       if (rv < 0)
-               return rv;
-
-       ar = file->private_data;
-       if (!ar)
-               return 0;
-       if (*pos >= ar->size)
-               return 0;
-       if (*pos + size > ar->size)
-               size = ar->size - *pos;
-       if (copy_to_user(buf, ar->data + *pos, size))
-               return -EFAULT;
-       *pos += size;
-       return size;
-}
-
-static int TA_open(struct inode *inode, struct file *file)
-{
-       file->private_data = NULL;
-       return 0;
-}
-
-static int TA_release(struct inode *inode, struct file *file)
-{
-       void *p = file->private_data;
-       file->private_data = NULL;
-       kfree(p);
-       return 0;
-}
-
 static struct file_operations transaction_ops = {
-       .write          = TA_write,
-       .read           = TA_read,
-       .open           = TA_open,
-       .release        = TA_release,
+       .write          = nfsctl_transaction_write,
+       .read           = simple_transaction_read,
+       .release        = simple_transaction_release,
 };
 
 extern struct seq_operations nfs_exports_op;
@@ -363,7 +296,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
        if (len)
                return len;
        
-       mesg = buf; len = PAGE_SIZE-sizeof(struct argresp);
+       mesg = buf; len = SIMPLE_TRANSACTION_LIMIT;
        qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
        mesg[-1] = '\n';
        return mesg - buf;      
@@ -393,6 +326,29 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
        return strlen(buf);
 }
 
+extern time_t nfs4_leasetime(void);
+
+static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
+{
+       /* if size > 10 seconds, call
+        * nfs4_reset_lease() then write out the new lease (seconds) as reply
+        */
+       char *mesg = buf;
+       int rv;
+
+       if (size > 0) {
+               int lease;
+               rv = get_int(&mesg, &lease);
+               if (rv)
+                       return rv;
+               if (lease < 10 || lease > 3600)
+                       return -EINVAL;
+               nfs4_reset_lease(lease);
+       }
+       sprintf(buf, "%ld\n", nfs4_lease_time());
+       return strlen(buf);
+}
+
 /*----------------------------------------------------------------------------*/
 /*
  *     populating the filesystem.
@@ -411,6 +367,9 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
                [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
                [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
+#ifdef CONFIG_NFSD_V4
+               [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
+#endif
                /* last one */ {""}
        };
        return simple_fill_super(sb, 0x6e667364, nfsd_files);
@@ -441,7 +400,7 @@ static int __init init_nfsd(void)
 #ifdef CONFIG_NFSD_V4
        nfsd_idmap_init();      /* Name to ID mapping */
 #endif /* CONFIG_NFSD_V4 */
-       if (proc_mkdir("fs/nfs", 0)) {
+       if (proc_mkdir("fs/nfs", NULL)) {
                struct proc_dir_entry *entry;
                entry = create_proc_entry("fs/nfs/exports", 0, NULL);
                if (entry)