bit which holds it in the pnfs_layout_hdr's list.  When the final lseg
 is removed from the pnfs_layout_hdr's list, the NFS_LAYOUT_DESTROYED
 bit is set, preventing any new lsegs from being added.
+
+layout drivers
+--------------
+
+PNFS utilizes what is called layout drivers. The STD defines 3 basic
+layout types: "files" "objects" and "blocks". For each of these types
+there is a layout-driver with a common function-vectors table which
+are called by the nfs-client pnfs-core to implement the different layout
+types.
+
+Files-layout-driver code is in: fs/nfs/nfs4filelayout.c && nfs4filelayoutdev.c
+Objects-layout-deriver code is in: fs/nfs/objlayout/.. directory
+Blocks-layout-deriver code is in: fs/nfs/blocklayout/.. directory
+
+objects-layout setup
+--------------------
+
+As part of the full STD implementation the objlayoutdriver.ko needs, at times,
+to automatically login to yet undiscovered iscsi/osd devices. For this the
+driver makes up-calles to a user-mode script called *osd_login*
+
+The path_name of the script to use is by default:
+       /sbin/osd_login.
+This name can be overridden by the Kernel module parameter:
+       objlayoutdriver.osd_login_prog
+
+If Kernel does not find the osd_login_prog path it will zero it out
+and will not attempt farther logins. An admin can then write new value
+to the objlayoutdriver.osd_login_prog Kernel parameter to re-enable it.
+
+The /sbin/osd_login is part of the nfs-utils package, and should usually
+be installed on distributions that support this Kernel version.
+
+The API to the login script is as follows:
+       Usage: $0 -u <URI> -o <OSDNAME> -s <SYSTEMID>
+       Options:
+               -u              target uri e.g. iscsi://<ip>:<port>
+                               (allways exists)
+                               (More protocols can be defined in the future.
+                                The client does not interpret this string it is
+                                passed unchanged as recieved from the Server)
+               -o              osdname of the requested target OSD
+                               (Might be empty)
+                               (A string which denotes the OSD name, there is a
+                                limit of 64 chars on this string)
+               -s              systemid of the requested target OSD
+                               (Might be empty)
+                               (This string, if not empty is always an hex
+                                representation of the 20 bytes osd_system_id)
+
+blocks-layout setup
+-------------------
+
+TODO: Document the setup needs of the blocks layout driver
 
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <linux/kmod.h>
+#include <linux/moduleparam.h>
+#include <linux/ratelimit.h>
 #include <scsi/osd_initiator.h>
 #include "objlayout.h"
 
        __free_page(odi->page);
        kfree(odi);
 }
+
+enum {
+       OBJLAYOUT_MAX_URI_LEN = 256, OBJLAYOUT_MAX_OSDNAME_LEN = 64,
+       OBJLAYOUT_MAX_SYSID_HEX_LEN = OSD_SYSTEMID_LEN * 2 + 1,
+       OSD_LOGIN_UPCALL_PATHLEN  = 256
+};
+
+static char osd_login_prog[OSD_LOGIN_UPCALL_PATHLEN] = "/sbin/osd_login";
+
+module_param_string(osd_login_prog, osd_login_prog, sizeof(osd_login_prog),
+                   0600);
+MODULE_PARM_DESC(osd_login_prog, "Path to the osd_login upcall program");
+
+struct __auto_login {
+       char uri[OBJLAYOUT_MAX_URI_LEN];
+       char osdname[OBJLAYOUT_MAX_OSDNAME_LEN];
+       char systemid_hex[OBJLAYOUT_MAX_SYSID_HEX_LEN];
+};
+
+static int __objlayout_upcall(struct __auto_login *login)
+{
+       static char *envp[] = { "HOME=/",
+               "TERM=linux",
+               "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+               NULL
+       };
+       char *argv[8];
+       int ret;
+
+       if (unlikely(!osd_login_prog[0])) {
+               dprintk("%s: osd_login_prog is disabled\n", __func__);
+               return -EACCES;
+       }
+
+       dprintk("%s uri: %s\n", __func__, login->uri);
+       dprintk("%s osdname %s\n", __func__, login->osdname);
+       dprintk("%s systemid_hex %s\n", __func__, login->systemid_hex);
+
+       argv[0] = (char *)osd_login_prog;
+       argv[1] = "-u";
+       argv[2] = login->uri;
+       argv[3] = "-o";
+       argv[4] = login->osdname;
+       argv[5] = "-s";
+       argv[6] = login->systemid_hex;
+       argv[7] = NULL;
+
+       ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+       /*
+        * Disable the upcall mechanism if we're getting an ENOENT or
+        * EACCES error. The admin can re-enable it on the fly by using
+        * sysfs to set the objlayoutdriver.osd_login_prog module parameter once
+        * the problem has been fixed.
+        */
+       if (ret == -ENOENT || ret == -EACCES) {
+               printk(KERN_ERR "PNFS-OBJ: %s was not found please set "
+                       "objlayoutdriver.osd_login_prog kernel parameter!\n",
+                       osd_login_prog);
+               osd_login_prog[0] = '\0';
+       }
+       dprintk("%s %s return value: %d\n", __func__, osd_login_prog, ret);
+
+       return ret;
+}
+
+/* Assume dest is all zeros */
+static void __copy_nfsS_and_zero_terminate(struct nfs4_string s,
+                                          char *dest, int max_len,
+                                          const char *var_name)
+{
+       if (!s.len)
+               return;
+
+       if (s.len >= max_len) {
+               pr_warn_ratelimited(
+                       "objlayout_autologin: %s: s.len(%d) >= max_len(%d)",
+                       var_name, s.len, max_len);
+               s.len = max_len - 1; /* space for null terminator */
+       }
+
+       memcpy(dest, s.data, s.len);
+}
+
+/* Assume sysid is all zeros */
+static void _sysid_2_hex(struct nfs4_string s,
+                 char sysid[OBJLAYOUT_MAX_SYSID_HEX_LEN])
+{
+       int i;
+       char *cur;
+
+       if (!s.len)
+               return;
+
+       if (s.len != OSD_SYSTEMID_LEN) {
+               pr_warn_ratelimited(
+                   "objlayout_autologin: systemid_len(%d) != OSD_SYSTEMID_LEN",
+                   s.len);
+               if (s.len > OSD_SYSTEMID_LEN)
+                       s.len = OSD_SYSTEMID_LEN;
+       }
+
+       cur = sysid;
+       for (i = 0; i < s.len; i++)
+               cur = hex_byte_pack(cur, s.data[i]);
+}
+
+int objlayout_autologin(struct pnfs_osd_deviceaddr *deviceaddr)
+{
+       int rc;
+       struct __auto_login login;
+
+       if (!deviceaddr->oda_targetaddr.ota_netaddr.r_addr.len)
+               return -ENODEV;
+
+       memset(&login, 0, sizeof(login));
+       __copy_nfsS_and_zero_terminate(
+               deviceaddr->oda_targetaddr.ota_netaddr.r_addr,
+               login.uri, sizeof(login.uri), "URI");
+
+       __copy_nfsS_and_zero_terminate(
+               deviceaddr->oda_osdname,
+               login.osdname, sizeof(login.osdname), "OSDNAME");
+
+       _sysid_2_hex(deviceaddr->oda_systemid, login.systemid_hex);
+
+       rc = __objlayout_upcall(&login);
+       if (rc > 0) /* script returns positive values */
+               rc = -ENODEV;
+
+       return rc;
+}