diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 464 |
1 files changed, 374 insertions, 90 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5879b23e0c9..003cb6955a2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -80,7 +80,10 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
80 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | 80 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, |
81 | struct nfs_fattr *fattr, struct iattr *sattr, | 81 | struct nfs_fattr *fattr, struct iattr *sattr, |
82 | struct nfs4_state *state); | 82 | struct nfs4_state *state); |
83 | 83 | #ifdef CONFIG_NFS_V4_1 | |
84 | static int nfs41_test_stateid(struct nfs_server *, struct nfs4_state *); | ||
85 | static int nfs41_free_stateid(struct nfs_server *, struct nfs4_state *); | ||
86 | #endif | ||
84 | /* Prevent leaks of NFSv4 errors into userland */ | 87 | /* Prevent leaks of NFSv4 errors into userland */ |
85 | static int nfs4_map_errors(int err) | 88 | static int nfs4_map_errors(int err) |
86 | { | 89 | { |
@@ -137,12 +140,13 @@ const u32 nfs4_pathconf_bitmap[2] = { | |||
137 | 0 | 140 | 0 |
138 | }; | 141 | }; |
139 | 142 | ||
140 | const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE | 143 | const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE |
141 | | FATTR4_WORD0_MAXREAD | 144 | | FATTR4_WORD0_MAXREAD |
142 | | FATTR4_WORD0_MAXWRITE | 145 | | FATTR4_WORD0_MAXWRITE |
143 | | FATTR4_WORD0_LEASE_TIME, | 146 | | FATTR4_WORD0_LEASE_TIME, |
144 | FATTR4_WORD1_TIME_DELTA | 147 | FATTR4_WORD1_TIME_DELTA |
145 | | FATTR4_WORD1_FS_LAYOUT_TYPES | 148 | | FATTR4_WORD1_FS_LAYOUT_TYPES, |
149 | FATTR4_WORD2_LAYOUT_BLKSIZE | ||
146 | }; | 150 | }; |
147 | 151 | ||
148 | const u32 nfs4_fs_locations_bitmap[2] = { | 152 | const u32 nfs4_fs_locations_bitmap[2] = { |
@@ -763,8 +767,8 @@ struct nfs4_opendata { | |||
763 | struct nfs_open_confirmres c_res; | 767 | struct nfs_open_confirmres c_res; |
764 | struct nfs_fattr f_attr; | 768 | struct nfs_fattr f_attr; |
765 | struct nfs_fattr dir_attr; | 769 | struct nfs_fattr dir_attr; |
766 | struct path path; | ||
767 | struct dentry *dir; | 770 | struct dentry *dir; |
771 | struct dentry *dentry; | ||
768 | struct nfs4_state_owner *owner; | 772 | struct nfs4_state_owner *owner; |
769 | struct nfs4_state *state; | 773 | struct nfs4_state *state; |
770 | struct iattr attrs; | 774 | struct iattr attrs; |
@@ -786,12 +790,12 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
786 | nfs_fattr_init(&p->dir_attr); | 790 | nfs_fattr_init(&p->dir_attr); |
787 | } | 791 | } |
788 | 792 | ||
789 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 793 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, |
790 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, | 794 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, |
791 | const struct iattr *attrs, | 795 | const struct iattr *attrs, |
792 | gfp_t gfp_mask) | 796 | gfp_t gfp_mask) |
793 | { | 797 | { |
794 | struct dentry *parent = dget_parent(path->dentry); | 798 | struct dentry *parent = dget_parent(dentry); |
795 | struct inode *dir = parent->d_inode; | 799 | struct inode *dir = parent->d_inode; |
796 | struct nfs_server *server = NFS_SERVER(dir); | 800 | struct nfs_server *server = NFS_SERVER(dir); |
797 | struct nfs4_opendata *p; | 801 | struct nfs4_opendata *p; |
@@ -802,8 +806,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
802 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); | 806 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); |
803 | if (p->o_arg.seqid == NULL) | 807 | if (p->o_arg.seqid == NULL) |
804 | goto err_free; | 808 | goto err_free; |
805 | path_get(path); | 809 | nfs_sb_active(dentry->d_sb); |
806 | p->path = *path; | 810 | p->dentry = dget(dentry); |
807 | p->dir = parent; | 811 | p->dir = parent; |
808 | p->owner = sp; | 812 | p->owner = sp; |
809 | atomic_inc(&sp->so_count); | 813 | atomic_inc(&sp->so_count); |
@@ -812,7 +816,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
812 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); | 816 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); |
813 | p->o_arg.clientid = server->nfs_client->cl_clientid; | 817 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
814 | p->o_arg.id = sp->so_owner_id.id; | 818 | p->o_arg.id = sp->so_owner_id.id; |
815 | p->o_arg.name = &p->path.dentry->d_name; | 819 | p->o_arg.name = &dentry->d_name; |
816 | p->o_arg.server = server; | 820 | p->o_arg.server = server; |
817 | p->o_arg.bitmask = server->attr_bitmask; | 821 | p->o_arg.bitmask = server->attr_bitmask; |
818 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 822 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
@@ -842,13 +846,15 @@ static void nfs4_opendata_free(struct kref *kref) | |||
842 | { | 846 | { |
843 | struct nfs4_opendata *p = container_of(kref, | 847 | struct nfs4_opendata *p = container_of(kref, |
844 | struct nfs4_opendata, kref); | 848 | struct nfs4_opendata, kref); |
849 | struct super_block *sb = p->dentry->d_sb; | ||
845 | 850 | ||
846 | nfs_free_seqid(p->o_arg.seqid); | 851 | nfs_free_seqid(p->o_arg.seqid); |
847 | if (p->state != NULL) | 852 | if (p->state != NULL) |
848 | nfs4_put_open_state(p->state); | 853 | nfs4_put_open_state(p->state); |
849 | nfs4_put_state_owner(p->owner); | 854 | nfs4_put_state_owner(p->owner); |
850 | dput(p->dir); | 855 | dput(p->dir); |
851 | path_put(&p->path); | 856 | dput(p->dentry); |
857 | nfs_sb_deactive(sb); | ||
852 | kfree(p); | 858 | kfree(p); |
853 | } | 859 | } |
854 | 860 | ||
@@ -1130,7 +1136,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
1130 | { | 1136 | { |
1131 | struct nfs4_opendata *opendata; | 1137 | struct nfs4_opendata *opendata; |
1132 | 1138 | ||
1133 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL, GFP_NOFS); | 1139 | opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, GFP_NOFS); |
1134 | if (opendata == NULL) | 1140 | if (opendata == NULL) |
1135 | return ERR_PTR(-ENOMEM); | 1141 | return ERR_PTR(-ENOMEM); |
1136 | opendata->state = state; | 1142 | opendata->state = state; |
@@ -1154,7 +1160,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod | |||
1154 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 1160 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
1155 | if (IS_ERR(newstate)) | 1161 | if (IS_ERR(newstate)) |
1156 | return PTR_ERR(newstate); | 1162 | return PTR_ERR(newstate); |
1157 | nfs4_close_state(&opendata->path, newstate, fmode); | 1163 | nfs4_close_state(newstate, fmode); |
1158 | *res = newstate; | 1164 | *res = newstate; |
1159 | return 0; | 1165 | return 0; |
1160 | } | 1166 | } |
@@ -1352,7 +1358,7 @@ static void nfs4_open_confirm_release(void *calldata) | |||
1352 | goto out_free; | 1358 | goto out_free; |
1353 | state = nfs4_opendata_to_nfs4_state(data); | 1359 | state = nfs4_opendata_to_nfs4_state(data); |
1354 | if (!IS_ERR(state)) | 1360 | if (!IS_ERR(state)) |
1355 | nfs4_close_state(&data->path, state, data->o_arg.fmode); | 1361 | nfs4_close_state(state, data->o_arg.fmode); |
1356 | out_free: | 1362 | out_free: |
1357 | nfs4_opendata_put(data); | 1363 | nfs4_opendata_put(data); |
1358 | } | 1364 | } |
@@ -1497,7 +1503,7 @@ static void nfs4_open_release(void *calldata) | |||
1497 | goto out_free; | 1503 | goto out_free; |
1498 | state = nfs4_opendata_to_nfs4_state(data); | 1504 | state = nfs4_opendata_to_nfs4_state(data); |
1499 | if (!IS_ERR(state)) | 1505 | if (!IS_ERR(state)) |
1500 | nfs4_close_state(&data->path, state, data->o_arg.fmode); | 1506 | nfs4_close_state(state, data->o_arg.fmode); |
1501 | out_free: | 1507 | out_free: |
1502 | nfs4_opendata_put(data); | 1508 | nfs4_opendata_put(data); |
1503 | } | 1509 | } |
@@ -1648,7 +1654,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s | |||
1648 | return PTR_ERR(opendata); | 1654 | return PTR_ERR(opendata); |
1649 | ret = nfs4_open_recover(opendata, state); | 1655 | ret = nfs4_open_recover(opendata, state); |
1650 | if (ret == -ESTALE) | 1656 | if (ret == -ESTALE) |
1651 | d_drop(ctx->path.dentry); | 1657 | d_drop(ctx->dentry); |
1652 | nfs4_opendata_put(opendata); | 1658 | nfs4_opendata_put(opendata); |
1653 | return ret; | 1659 | return ret; |
1654 | } | 1660 | } |
@@ -1687,6 +1693,20 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
1687 | return ret; | 1693 | return ret; |
1688 | } | 1694 | } |
1689 | 1695 | ||
1696 | #if defined(CONFIG_NFS_V4_1) | ||
1697 | static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | ||
1698 | { | ||
1699 | int status; | ||
1700 | struct nfs_server *server = NFS_SERVER(state->inode); | ||
1701 | |||
1702 | status = nfs41_test_stateid(server, state); | ||
1703 | if (status == NFS_OK) | ||
1704 | return 0; | ||
1705 | nfs41_free_stateid(server, state); | ||
1706 | return nfs4_open_expired(sp, state); | ||
1707 | } | ||
1708 | #endif | ||
1709 | |||
1690 | /* | 1710 | /* |
1691 | * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-* | 1711 | * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-* |
1692 | * fields corresponding to attributes that were used to store the verifier. | 1712 | * fields corresponding to attributes that were used to store the verifier. |
@@ -1706,7 +1726,7 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct | |||
1706 | /* | 1726 | /* |
1707 | * Returns a referenced nfs4_state | 1727 | * Returns a referenced nfs4_state |
1708 | */ | 1728 | */ |
1709 | static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | 1729 | static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) |
1710 | { | 1730 | { |
1711 | struct nfs4_state_owner *sp; | 1731 | struct nfs4_state_owner *sp; |
1712 | struct nfs4_state *state = NULL; | 1732 | struct nfs4_state *state = NULL; |
@@ -1723,15 +1743,15 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
1723 | status = nfs4_recover_expired_lease(server); | 1743 | status = nfs4_recover_expired_lease(server); |
1724 | if (status != 0) | 1744 | if (status != 0) |
1725 | goto err_put_state_owner; | 1745 | goto err_put_state_owner; |
1726 | if (path->dentry->d_inode != NULL) | 1746 | if (dentry->d_inode != NULL) |
1727 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); | 1747 | nfs4_return_incompatible_delegation(dentry->d_inode, fmode); |
1728 | status = -ENOMEM; | 1748 | status = -ENOMEM; |
1729 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr, GFP_KERNEL); | 1749 | opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, GFP_KERNEL); |
1730 | if (opendata == NULL) | 1750 | if (opendata == NULL) |
1731 | goto err_put_state_owner; | 1751 | goto err_put_state_owner; |
1732 | 1752 | ||
1733 | if (path->dentry->d_inode != NULL) | 1753 | if (dentry->d_inode != NULL) |
1734 | opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); | 1754 | opendata->state = nfs4_get_open_state(dentry->d_inode, sp); |
1735 | 1755 | ||
1736 | status = _nfs4_proc_open(opendata); | 1756 | status = _nfs4_proc_open(opendata); |
1737 | if (status != 0) | 1757 | if (status != 0) |
@@ -1769,14 +1789,14 @@ out_err: | |||
1769 | } | 1789 | } |
1770 | 1790 | ||
1771 | 1791 | ||
1772 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred) | 1792 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred) |
1773 | { | 1793 | { |
1774 | struct nfs4_exception exception = { }; | 1794 | struct nfs4_exception exception = { }; |
1775 | struct nfs4_state *res; | 1795 | struct nfs4_state *res; |
1776 | int status; | 1796 | int status; |
1777 | 1797 | ||
1778 | do { | 1798 | do { |
1779 | status = _nfs4_do_open(dir, path, fmode, flags, sattr, cred, &res); | 1799 | status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, &res); |
1780 | if (status == 0) | 1800 | if (status == 0) |
1781 | break; | 1801 | break; |
1782 | /* NOTE: BAD_SEQID means the server and client disagree about the | 1802 | /* NOTE: BAD_SEQID means the server and client disagree about the |
@@ -1873,7 +1893,6 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1873 | } | 1893 | } |
1874 | 1894 | ||
1875 | struct nfs4_closedata { | 1895 | struct nfs4_closedata { |
1876 | struct path path; | ||
1877 | struct inode *inode; | 1896 | struct inode *inode; |
1878 | struct nfs4_state *state; | 1897 | struct nfs4_state *state; |
1879 | struct nfs_closeargs arg; | 1898 | struct nfs_closeargs arg; |
@@ -1888,13 +1907,14 @@ static void nfs4_free_closedata(void *data) | |||
1888 | { | 1907 | { |
1889 | struct nfs4_closedata *calldata = data; | 1908 | struct nfs4_closedata *calldata = data; |
1890 | struct nfs4_state_owner *sp = calldata->state->owner; | 1909 | struct nfs4_state_owner *sp = calldata->state->owner; |
1910 | struct super_block *sb = calldata->state->inode->i_sb; | ||
1891 | 1911 | ||
1892 | if (calldata->roc) | 1912 | if (calldata->roc) |
1893 | pnfs_roc_release(calldata->state->inode); | 1913 | pnfs_roc_release(calldata->state->inode); |
1894 | nfs4_put_open_state(calldata->state); | 1914 | nfs4_put_open_state(calldata->state); |
1895 | nfs_free_seqid(calldata->arg.seqid); | 1915 | nfs_free_seqid(calldata->arg.seqid); |
1896 | nfs4_put_state_owner(sp); | 1916 | nfs4_put_state_owner(sp); |
1897 | path_put(&calldata->path); | 1917 | nfs_sb_deactive(sb); |
1898 | kfree(calldata); | 1918 | kfree(calldata); |
1899 | } | 1919 | } |
1900 | 1920 | ||
@@ -2014,7 +2034,7 @@ static const struct rpc_call_ops nfs4_close_ops = { | |||
2014 | * | 2034 | * |
2015 | * NOTE: Caller must be holding the sp->so_owner semaphore! | 2035 | * NOTE: Caller must be holding the sp->so_owner semaphore! |
2016 | */ | 2036 | */ |
2017 | int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) | 2037 | int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) |
2018 | { | 2038 | { |
2019 | struct nfs_server *server = NFS_SERVER(state->inode); | 2039 | struct nfs_server *server = NFS_SERVER(state->inode); |
2020 | struct nfs4_closedata *calldata; | 2040 | struct nfs4_closedata *calldata; |
@@ -2050,8 +2070,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i | |||
2050 | calldata->res.seqid = calldata->arg.seqid; | 2070 | calldata->res.seqid = calldata->arg.seqid; |
2051 | calldata->res.server = server; | 2071 | calldata->res.server = server; |
2052 | calldata->roc = roc; | 2072 | calldata->roc = roc; |
2053 | path_get(path); | 2073 | nfs_sb_active(calldata->inode->i_sb); |
2054 | calldata->path = *path; | ||
2055 | 2074 | ||
2056 | msg.rpc_argp = &calldata->arg; | 2075 | msg.rpc_argp = &calldata->arg; |
2057 | msg.rpc_resp = &calldata->res; | 2076 | msg.rpc_resp = &calldata->res; |
@@ -2080,7 +2099,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags | |||
2080 | struct nfs4_state *state; | 2099 | struct nfs4_state *state; |
2081 | 2100 | ||
2082 | /* Protect against concurrent sillydeletes */ | 2101 | /* Protect against concurrent sillydeletes */ |
2083 | state = nfs4_do_open(dir, &ctx->path, ctx->mode, open_flags, attr, ctx->cred); | 2102 | state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, ctx->cred); |
2084 | if (IS_ERR(state)) | 2103 | if (IS_ERR(state)) |
2085 | return ERR_CAST(state); | 2104 | return ERR_CAST(state); |
2086 | ctx->state = state; | 2105 | ctx->state = state; |
@@ -2092,9 +2111,9 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | |||
2092 | if (ctx->state == NULL) | 2111 | if (ctx->state == NULL) |
2093 | return; | 2112 | return; |
2094 | if (is_sync) | 2113 | if (is_sync) |
2095 | nfs4_close_sync(&ctx->path, ctx->state, ctx->mode); | 2114 | nfs4_close_sync(ctx->state, ctx->mode); |
2096 | else | 2115 | else |
2097 | nfs4_close_state(&ctx->path, ctx->state, ctx->mode); | 2116 | nfs4_close_state(ctx->state, ctx->mode); |
2098 | } | 2117 | } |
2099 | 2118 | ||
2100 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 2119 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
@@ -2251,13 +2270,14 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2251 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2270 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, |
2252 | struct nfs_fsinfo *info) | 2271 | struct nfs_fsinfo *info) |
2253 | { | 2272 | { |
2273 | int minor_version = server->nfs_client->cl_minorversion; | ||
2254 | int status = nfs4_lookup_root(server, fhandle, info); | 2274 | int status = nfs4_lookup_root(server, fhandle, info); |
2255 | if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) | 2275 | if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) |
2256 | /* | 2276 | /* |
2257 | * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM | 2277 | * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM |
2258 | * by nfs4_map_errors() as this function exits. | 2278 | * by nfs4_map_errors() as this function exits. |
2259 | */ | 2279 | */ |
2260 | status = nfs4_find_root_sec(server, fhandle, info); | 2280 | status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info); |
2261 | if (status == 0) | 2281 | if (status == 0) |
2262 | status = nfs4_server_capabilities(server, fhandle); | 2282 | status = nfs4_server_capabilities(server, fhandle); |
2263 | if (status == 0) | 2283 | if (status == 0) |
@@ -2616,10 +2636,7 @@ static int | |||
2616 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 2636 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
2617 | int flags, struct nfs_open_context *ctx) | 2637 | int flags, struct nfs_open_context *ctx) |
2618 | { | 2638 | { |
2619 | struct path my_path = { | 2639 | struct dentry *de = dentry; |
2620 | .dentry = dentry, | ||
2621 | }; | ||
2622 | struct path *path = &my_path; | ||
2623 | struct nfs4_state *state; | 2640 | struct nfs4_state *state; |
2624 | struct rpc_cred *cred = NULL; | 2641 | struct rpc_cred *cred = NULL; |
2625 | fmode_t fmode = 0; | 2642 | fmode_t fmode = 0; |
@@ -2627,11 +2644,11 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
2627 | 2644 | ||
2628 | if (ctx != NULL) { | 2645 | if (ctx != NULL) { |
2629 | cred = ctx->cred; | 2646 | cred = ctx->cred; |
2630 | path = &ctx->path; | 2647 | de = ctx->dentry; |
2631 | fmode = ctx->mode; | 2648 | fmode = ctx->mode; |
2632 | } | 2649 | } |
2633 | sattr->ia_mode &= ~current_umask(); | 2650 | sattr->ia_mode &= ~current_umask(); |
2634 | state = nfs4_do_open(dir, path, fmode, flags, sattr, cred); | 2651 | state = nfs4_do_open(dir, de, fmode, flags, sattr, cred); |
2635 | d_drop(dentry); | 2652 | d_drop(dentry); |
2636 | if (IS_ERR(state)) { | 2653 | if (IS_ERR(state)) { |
2637 | status = PTR_ERR(state); | 2654 | status = PTR_ERR(state); |
@@ -2642,7 +2659,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
2642 | if (ctx != NULL) | 2659 | if (ctx != NULL) |
2643 | ctx->state = state; | 2660 | ctx->state = state; |
2644 | else | 2661 | else |
2645 | nfs4_close_sync(path, state, fmode); | 2662 | nfs4_close_sync(state, fmode); |
2646 | out: | 2663 | out: |
2647 | return status; | 2664 | return status; |
2648 | } | 2665 | } |
@@ -3357,9 +3374,13 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata) | |||
3357 | 3374 | ||
3358 | if (task->tk_status < 0) { | 3375 | if (task->tk_status < 0) { |
3359 | /* Unless we're shutting down, schedule state recovery! */ | 3376 | /* Unless we're shutting down, schedule state recovery! */ |
3360 | if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) != 0) | 3377 | if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0) |
3378 | return; | ||
3379 | if (task->tk_status != NFS4ERR_CB_PATH_DOWN) { | ||
3361 | nfs4_schedule_lease_recovery(clp); | 3380 | nfs4_schedule_lease_recovery(clp); |
3362 | return; | 3381 | return; |
3382 | } | ||
3383 | nfs4_schedule_path_down_recovery(clp); | ||
3363 | } | 3384 | } |
3364 | do_renew_lease(clp, timestamp); | 3385 | do_renew_lease(clp, timestamp); |
3365 | } | 3386 | } |
@@ -3369,7 +3390,7 @@ static const struct rpc_call_ops nfs4_renew_ops = { | |||
3369 | .rpc_release = nfs4_renew_release, | 3390 | .rpc_release = nfs4_renew_release, |
3370 | }; | 3391 | }; |
3371 | 3392 | ||
3372 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3393 | static int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags) |
3373 | { | 3394 | { |
3374 | struct rpc_message msg = { | 3395 | struct rpc_message msg = { |
3375 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 3396 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
@@ -3378,9 +3399,11 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
3378 | }; | 3399 | }; |
3379 | struct nfs4_renewdata *data; | 3400 | struct nfs4_renewdata *data; |
3380 | 3401 | ||
3402 | if (renew_flags == 0) | ||
3403 | return 0; | ||
3381 | if (!atomic_inc_not_zero(&clp->cl_count)) | 3404 | if (!atomic_inc_not_zero(&clp->cl_count)) |
3382 | return -EIO; | 3405 | return -EIO; |
3383 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 3406 | data = kmalloc(sizeof(*data), GFP_NOFS); |
3384 | if (data == NULL) | 3407 | if (data == NULL) |
3385 | return -ENOMEM; | 3408 | return -ENOMEM; |
3386 | data->client = clp; | 3409 | data->client = clp; |
@@ -3389,7 +3412,7 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
3389 | &nfs4_renew_ops, data); | 3412 | &nfs4_renew_ops, data); |
3390 | } | 3413 | } |
3391 | 3414 | ||
3392 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3415 | static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
3393 | { | 3416 | { |
3394 | struct rpc_message msg = { | 3417 | struct rpc_message msg = { |
3395 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 3418 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
@@ -3419,19 +3442,6 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server) | |||
3419 | */ | 3442 | */ |
3420 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) | 3443 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) |
3421 | 3444 | ||
3422 | static void buf_to_pages(const void *buf, size_t buflen, | ||
3423 | struct page **pages, unsigned int *pgbase) | ||
3424 | { | ||
3425 | const void *p = buf; | ||
3426 | |||
3427 | *pgbase = offset_in_page(buf); | ||
3428 | p -= *pgbase; | ||
3429 | while (p < buf + buflen) { | ||
3430 | *(pages++) = virt_to_page(p); | ||
3431 | p += PAGE_CACHE_SIZE; | ||
3432 | } | ||
3433 | } | ||
3434 | |||
3435 | static int buf_to_pages_noslab(const void *buf, size_t buflen, | 3445 | static int buf_to_pages_noslab(const void *buf, size_t buflen, |
3436 | struct page **pages, unsigned int *pgbase) | 3446 | struct page **pages, unsigned int *pgbase) |
3437 | { | 3447 | { |
@@ -3528,9 +3538,19 @@ out: | |||
3528 | nfs4_set_cached_acl(inode, acl); | 3538 | nfs4_set_cached_acl(inode, acl); |
3529 | } | 3539 | } |
3530 | 3540 | ||
3541 | /* | ||
3542 | * The getxattr API returns the required buffer length when called with a | ||
3543 | * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating | ||
3544 | * the required buf. On a NULL buf, we send a page of data to the server | ||
3545 | * guessing that the ACL request can be serviced by a page. If so, we cache | ||
3546 | * up to the page of ACL data, and the 2nd call to getxattr is serviced by | ||
3547 | * the cache. If not so, we throw away the page, and cache the required | ||
3548 | * length. The next getxattr call will then produce another round trip to | ||
3549 | * the server, this time with the input buf of the required size. | ||
3550 | */ | ||
3531 | static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | 3551 | static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) |
3532 | { | 3552 | { |
3533 | struct page *pages[NFS4ACL_MAXPAGES]; | 3553 | struct page *pages[NFS4ACL_MAXPAGES] = {NULL, }; |
3534 | struct nfs_getaclargs args = { | 3554 | struct nfs_getaclargs args = { |
3535 | .fh = NFS_FH(inode), | 3555 | .fh = NFS_FH(inode), |
3536 | .acl_pages = pages, | 3556 | .acl_pages = pages, |
@@ -3545,41 +3565,60 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3545 | .rpc_argp = &args, | 3565 | .rpc_argp = &args, |
3546 | .rpc_resp = &res, | 3566 | .rpc_resp = &res, |
3547 | }; | 3567 | }; |
3548 | struct page *localpage = NULL; | 3568 | int ret = -ENOMEM, npages, i, acl_len = 0; |
3549 | int ret; | ||
3550 | 3569 | ||
3551 | if (buflen < PAGE_SIZE) { | 3570 | npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; |
3552 | /* As long as we're doing a round trip to the server anyway, | 3571 | /* As long as we're doing a round trip to the server anyway, |
3553 | * let's be prepared for a page of acl data. */ | 3572 | * let's be prepared for a page of acl data. */ |
3554 | localpage = alloc_page(GFP_KERNEL); | 3573 | if (npages == 0) |
3555 | resp_buf = page_address(localpage); | 3574 | npages = 1; |
3556 | if (localpage == NULL) | 3575 | |
3557 | return -ENOMEM; | 3576 | for (i = 0; i < npages; i++) { |
3558 | args.acl_pages[0] = localpage; | 3577 | pages[i] = alloc_page(GFP_KERNEL); |
3559 | args.acl_pgbase = 0; | 3578 | if (!pages[i]) |
3560 | args.acl_len = PAGE_SIZE; | 3579 | goto out_free; |
3561 | } else { | ||
3562 | resp_buf = buf; | ||
3563 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | ||
3564 | } | 3580 | } |
3565 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); | 3581 | if (npages > 1) { |
3582 | /* for decoding across pages */ | ||
3583 | args.acl_scratch = alloc_page(GFP_KERNEL); | ||
3584 | if (!args.acl_scratch) | ||
3585 | goto out_free; | ||
3586 | } | ||
3587 | args.acl_len = npages * PAGE_SIZE; | ||
3588 | args.acl_pgbase = 0; | ||
3589 | /* Let decode_getfacl know not to fail if the ACL data is larger than | ||
3590 | * the page we send as a guess */ | ||
3591 | if (buf == NULL) | ||
3592 | res.acl_flags |= NFS4_ACL_LEN_REQUEST; | ||
3593 | resp_buf = page_address(pages[0]); | ||
3594 | |||
3595 | dprintk("%s buf %p buflen %ld npages %d args.acl_len %ld\n", | ||
3596 | __func__, buf, buflen, npages, args.acl_len); | ||
3597 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), | ||
3598 | &msg, &args.seq_args, &res.seq_res, 0); | ||
3566 | if (ret) | 3599 | if (ret) |
3567 | goto out_free; | 3600 | goto out_free; |
3568 | if (res.acl_len > args.acl_len) | 3601 | |
3569 | nfs4_write_cached_acl(inode, NULL, res.acl_len); | 3602 | acl_len = res.acl_len - res.acl_data_offset; |
3603 | if (acl_len > args.acl_len) | ||
3604 | nfs4_write_cached_acl(inode, NULL, acl_len); | ||
3570 | else | 3605 | else |
3571 | nfs4_write_cached_acl(inode, resp_buf, res.acl_len); | 3606 | nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset, |
3607 | acl_len); | ||
3572 | if (buf) { | 3608 | if (buf) { |
3573 | ret = -ERANGE; | 3609 | ret = -ERANGE; |
3574 | if (res.acl_len > buflen) | 3610 | if (acl_len > buflen) |
3575 | goto out_free; | 3611 | goto out_free; |
3576 | if (localpage) | 3612 | _copy_from_pages(buf, pages, res.acl_data_offset, |
3577 | memcpy(buf, resp_buf, res.acl_len); | 3613 | res.acl_len); |
3578 | } | 3614 | } |
3579 | ret = res.acl_len; | 3615 | ret = acl_len; |
3580 | out_free: | 3616 | out_free: |
3581 | if (localpage) | 3617 | for (i = 0; i < npages; i++) |
3582 | __free_page(localpage); | 3618 | if (pages[i]) |
3619 | __free_page(pages[i]); | ||
3620 | if (args.acl_scratch) | ||
3621 | __free_page(args.acl_scratch); | ||
3583 | return ret; | 3622 | return ret; |
3584 | } | 3623 | } |
3585 | 3624 | ||
@@ -3610,6 +3649,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
3610 | nfs_zap_acl_cache(inode); | 3649 | nfs_zap_acl_cache(inode); |
3611 | ret = nfs4_read_cached_acl(inode, buf, buflen); | 3650 | ret = nfs4_read_cached_acl(inode, buf, buflen); |
3612 | if (ret != -ENOENT) | 3651 | if (ret != -ENOENT) |
3652 | /* -ENOENT is returned if there is no ACL or if there is an ACL | ||
3653 | * but no cached acl data, just the acl length */ | ||
3613 | return ret; | 3654 | return ret; |
3614 | return nfs4_get_acl_uncached(inode, buf, buflen); | 3655 | return nfs4_get_acl_uncached(inode, buf, buflen); |
3615 | } | 3656 | } |
@@ -4294,7 +4335,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
4294 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, | 4335 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, |
4295 | sizeof(data->lsp->ls_stateid.data)); | 4336 | sizeof(data->lsp->ls_stateid.data)); |
4296 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 4337 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; |
4297 | renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); | 4338 | renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); |
4298 | } | 4339 | } |
4299 | out: | 4340 | out: |
4300 | dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status); | 4341 | dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status); |
@@ -4443,6 +4484,20 @@ out: | |||
4443 | return err; | 4484 | return err; |
4444 | } | 4485 | } |
4445 | 4486 | ||
4487 | #if defined(CONFIG_NFS_V4_1) | ||
4488 | static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request) | ||
4489 | { | ||
4490 | int status; | ||
4491 | struct nfs_server *server = NFS_SERVER(state->inode); | ||
4492 | |||
4493 | status = nfs41_test_stateid(server, state); | ||
4494 | if (status == NFS_OK) | ||
4495 | return 0; | ||
4496 | nfs41_free_stateid(server, state); | ||
4497 | return nfs4_lock_expired(state, request); | ||
4498 | } | ||
4499 | #endif | ||
4500 | |||
4446 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 4501 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
4447 | { | 4502 | { |
4448 | struct nfs_inode *nfsi = NFS_I(state->inode); | 4503 | struct nfs_inode *nfsi = NFS_I(state->inode); |
@@ -4781,6 +4836,16 @@ out_inval: | |||
4781 | return -NFS4ERR_INVAL; | 4836 | return -NFS4ERR_INVAL; |
4782 | } | 4837 | } |
4783 | 4838 | ||
4839 | static bool | ||
4840 | nfs41_same_server_scope(struct server_scope *a, struct server_scope *b) | ||
4841 | { | ||
4842 | if (a->server_scope_sz == b->server_scope_sz && | ||
4843 | memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0) | ||
4844 | return true; | ||
4845 | |||
4846 | return false; | ||
4847 | } | ||
4848 | |||
4784 | /* | 4849 | /* |
4785 | * nfs4_proc_exchange_id() | 4850 | * nfs4_proc_exchange_id() |
4786 | * | 4851 | * |
@@ -4823,9 +4888,31 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4823 | init_utsname()->domainname, | 4888 | init_utsname()->domainname, |
4824 | clp->cl_rpcclient->cl_auth->au_flavor); | 4889 | clp->cl_rpcclient->cl_auth->au_flavor); |
4825 | 4890 | ||
4891 | res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL); | ||
4892 | if (unlikely(!res.server_scope)) | ||
4893 | return -ENOMEM; | ||
4894 | |||
4826 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 4895 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
4827 | if (!status) | 4896 | if (!status) |
4828 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); | 4897 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); |
4898 | |||
4899 | if (!status) { | ||
4900 | if (clp->server_scope && | ||
4901 | !nfs41_same_server_scope(clp->server_scope, | ||
4902 | res.server_scope)) { | ||
4903 | dprintk("%s: server_scope mismatch detected\n", | ||
4904 | __func__); | ||
4905 | set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state); | ||
4906 | kfree(clp->server_scope); | ||
4907 | clp->server_scope = NULL; | ||
4908 | } | ||
4909 | |||
4910 | if (!clp->server_scope) | ||
4911 | clp->server_scope = res.server_scope; | ||
4912 | else | ||
4913 | kfree(res.server_scope); | ||
4914 | } | ||
4915 | |||
4829 | dprintk("<-- %s status= %d\n", __func__, status); | 4916 | dprintk("<-- %s status= %d\n", __func__, status); |
4830 | return status; | 4917 | return status; |
4831 | } | 4918 | } |
@@ -5441,11 +5528,13 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_ | |||
5441 | return rpc_run_task(&task_setup_data); | 5528 | return rpc_run_task(&task_setup_data); |
5442 | } | 5529 | } |
5443 | 5530 | ||
5444 | static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred) | 5531 | static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags) |
5445 | { | 5532 | { |
5446 | struct rpc_task *task; | 5533 | struct rpc_task *task; |
5447 | int ret = 0; | 5534 | int ret = 0; |
5448 | 5535 | ||
5536 | if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) | ||
5537 | return 0; | ||
5449 | task = _nfs41_proc_sequence(clp, cred); | 5538 | task = _nfs41_proc_sequence(clp, cred); |
5450 | if (IS_ERR(task)) | 5539 | if (IS_ERR(task)) |
5451 | ret = PTR_ERR(task); | 5540 | ret = PTR_ERR(task); |
@@ -5706,7 +5795,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) | |||
5706 | { | 5795 | { |
5707 | struct nfs4_layoutreturn *lrp = calldata; | 5796 | struct nfs4_layoutreturn *lrp = calldata; |
5708 | struct nfs_server *server; | 5797 | struct nfs_server *server; |
5709 | struct pnfs_layout_hdr *lo = NFS_I(lrp->args.inode)->layout; | 5798 | struct pnfs_layout_hdr *lo = lrp->args.layout; |
5710 | 5799 | ||
5711 | dprintk("--> %s\n", __func__); | 5800 | dprintk("--> %s\n", __func__); |
5712 | 5801 | ||
@@ -5735,7 +5824,7 @@ static void nfs4_layoutreturn_release(void *calldata) | |||
5735 | struct nfs4_layoutreturn *lrp = calldata; | 5824 | struct nfs4_layoutreturn *lrp = calldata; |
5736 | 5825 | ||
5737 | dprintk("--> %s\n", __func__); | 5826 | dprintk("--> %s\n", __func__); |
5738 | put_layout_hdr(NFS_I(lrp->args.inode)->layout); | 5827 | put_layout_hdr(lrp->args.layout); |
5739 | kfree(calldata); | 5828 | kfree(calldata); |
5740 | dprintk("<-- %s\n", __func__); | 5829 | dprintk("<-- %s\n", __func__); |
5741 | } | 5830 | } |
@@ -5772,6 +5861,54 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp) | |||
5772 | return status; | 5861 | return status; |
5773 | } | 5862 | } |
5774 | 5863 | ||
5864 | /* | ||
5865 | * Retrieve the list of Data Server devices from the MDS. | ||
5866 | */ | ||
5867 | static int _nfs4_getdevicelist(struct nfs_server *server, | ||
5868 | const struct nfs_fh *fh, | ||
5869 | struct pnfs_devicelist *devlist) | ||
5870 | { | ||
5871 | struct nfs4_getdevicelist_args args = { | ||
5872 | .fh = fh, | ||
5873 | .layoutclass = server->pnfs_curr_ld->id, | ||
5874 | }; | ||
5875 | struct nfs4_getdevicelist_res res = { | ||
5876 | .devlist = devlist, | ||
5877 | }; | ||
5878 | struct rpc_message msg = { | ||
5879 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICELIST], | ||
5880 | .rpc_argp = &args, | ||
5881 | .rpc_resp = &res, | ||
5882 | }; | ||
5883 | int status; | ||
5884 | |||
5885 | dprintk("--> %s\n", __func__); | ||
5886 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, | ||
5887 | &res.seq_res, 0); | ||
5888 | dprintk("<-- %s status=%d\n", __func__, status); | ||
5889 | return status; | ||
5890 | } | ||
5891 | |||
5892 | int nfs4_proc_getdevicelist(struct nfs_server *server, | ||
5893 | const struct nfs_fh *fh, | ||
5894 | struct pnfs_devicelist *devlist) | ||
5895 | { | ||
5896 | struct nfs4_exception exception = { }; | ||
5897 | int err; | ||
5898 | |||
5899 | do { | ||
5900 | err = nfs4_handle_exception(server, | ||
5901 | _nfs4_getdevicelist(server, fh, devlist), | ||
5902 | &exception); | ||
5903 | } while (exception.retry); | ||
5904 | |||
5905 | dprintk("%s: err=%d, num_devs=%u\n", __func__, | ||
5906 | err, devlist->num_devs); | ||
5907 | |||
5908 | return err; | ||
5909 | } | ||
5910 | EXPORT_SYMBOL_GPL(nfs4_proc_getdevicelist); | ||
5911 | |||
5775 | static int | 5912 | static int |
5776 | _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | 5913 | _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) |
5777 | { | 5914 | { |
@@ -5850,9 +5987,16 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) | |||
5850 | static void nfs4_layoutcommit_release(void *calldata) | 5987 | static void nfs4_layoutcommit_release(void *calldata) |
5851 | { | 5988 | { |
5852 | struct nfs4_layoutcommit_data *data = calldata; | 5989 | struct nfs4_layoutcommit_data *data = calldata; |
5990 | struct pnfs_layout_segment *lseg, *tmp; | ||
5853 | 5991 | ||
5992 | pnfs_cleanup_layoutcommit(data); | ||
5854 | /* Matched by references in pnfs_set_layoutcommit */ | 5993 | /* Matched by references in pnfs_set_layoutcommit */ |
5855 | put_lseg(data->lseg); | 5994 | list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) { |
5995 | list_del_init(&lseg->pls_lc_list); | ||
5996 | if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, | ||
5997 | &lseg->pls_flags)) | ||
5998 | put_lseg(lseg); | ||
5999 | } | ||
5856 | put_rpccred(data->cred); | 6000 | put_rpccred(data->cred); |
5857 | kfree(data); | 6001 | kfree(data); |
5858 | } | 6002 | } |
@@ -5903,6 +6047,143 @@ out: | |||
5903 | rpc_put_task(task); | 6047 | rpc_put_task(task); |
5904 | return status; | 6048 | return status; |
5905 | } | 6049 | } |
6050 | |||
6051 | static int | ||
6052 | _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle, | ||
6053 | struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors) | ||
6054 | { | ||
6055 | struct nfs41_secinfo_no_name_args args = { | ||
6056 | .style = SECINFO_STYLE_CURRENT_FH, | ||
6057 | }; | ||
6058 | struct nfs4_secinfo_res res = { | ||
6059 | .flavors = flavors, | ||
6060 | }; | ||
6061 | struct rpc_message msg = { | ||
6062 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO_NO_NAME], | ||
6063 | .rpc_argp = &args, | ||
6064 | .rpc_resp = &res, | ||
6065 | }; | ||
6066 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); | ||
6067 | } | ||
6068 | |||
6069 | static int | ||
6070 | nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle, | ||
6071 | struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors) | ||
6072 | { | ||
6073 | struct nfs4_exception exception = { }; | ||
6074 | int err; | ||
6075 | do { | ||
6076 | err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors); | ||
6077 | switch (err) { | ||
6078 | case 0: | ||
6079 | case -NFS4ERR_WRONGSEC: | ||
6080 | case -NFS4ERR_NOTSUPP: | ||
6081 | break; | ||
6082 | default: | ||
6083 | err = nfs4_handle_exception(server, err, &exception); | ||
6084 | } | ||
6085 | } while (exception.retry); | ||
6086 | return err; | ||
6087 | } | ||
6088 | |||
6089 | static int | ||
6090 | nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | ||
6091 | struct nfs_fsinfo *info) | ||
6092 | { | ||
6093 | int err; | ||
6094 | struct page *page; | ||
6095 | rpc_authflavor_t flavor; | ||
6096 | struct nfs4_secinfo_flavors *flavors; | ||
6097 | |||
6098 | page = alloc_page(GFP_KERNEL); | ||
6099 | if (!page) { | ||
6100 | err = -ENOMEM; | ||
6101 | goto out; | ||
6102 | } | ||
6103 | |||
6104 | flavors = page_address(page); | ||
6105 | err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors); | ||
6106 | |||
6107 | /* | ||
6108 | * Fall back on "guess and check" method if | ||
6109 | * the server doesn't support SECINFO_NO_NAME | ||
6110 | */ | ||
6111 | if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) { | ||
6112 | err = nfs4_find_root_sec(server, fhandle, info); | ||
6113 | goto out_freepage; | ||
6114 | } | ||
6115 | if (err) | ||
6116 | goto out_freepage; | ||
6117 | |||
6118 | flavor = nfs_find_best_sec(flavors); | ||
6119 | if (err == 0) | ||
6120 | err = nfs4_lookup_root_sec(server, fhandle, info, flavor); | ||
6121 | |||
6122 | out_freepage: | ||
6123 | put_page(page); | ||
6124 | if (err == -EACCES) | ||
6125 | return -EPERM; | ||
6126 | out: | ||
6127 | return err; | ||
6128 | } | ||
6129 | static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state) | ||
6130 | { | ||
6131 | int status; | ||
6132 | struct nfs41_test_stateid_args args = { | ||
6133 | .stateid = &state->stateid, | ||
6134 | }; | ||
6135 | struct nfs41_test_stateid_res res; | ||
6136 | struct rpc_message msg = { | ||
6137 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], | ||
6138 | .rpc_argp = &args, | ||
6139 | .rpc_resp = &res, | ||
6140 | }; | ||
6141 | args.seq_args.sa_session = res.seq_res.sr_session = NULL; | ||
6142 | status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1); | ||
6143 | return status; | ||
6144 | } | ||
6145 | |||
6146 | static int nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state) | ||
6147 | { | ||
6148 | struct nfs4_exception exception = { }; | ||
6149 | int err; | ||
6150 | do { | ||
6151 | err = nfs4_handle_exception(server, | ||
6152 | _nfs41_test_stateid(server, state), | ||
6153 | &exception); | ||
6154 | } while (exception.retry); | ||
6155 | return err; | ||
6156 | } | ||
6157 | |||
6158 | static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *state) | ||
6159 | { | ||
6160 | int status; | ||
6161 | struct nfs41_free_stateid_args args = { | ||
6162 | .stateid = &state->stateid, | ||
6163 | }; | ||
6164 | struct nfs41_free_stateid_res res; | ||
6165 | struct rpc_message msg = { | ||
6166 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], | ||
6167 | .rpc_argp = &args, | ||
6168 | .rpc_resp = &res, | ||
6169 | }; | ||
6170 | |||
6171 | args.seq_args.sa_session = res.seq_res.sr_session = NULL; | ||
6172 | status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1); | ||
6173 | return status; | ||
6174 | } | ||
6175 | |||
6176 | static int nfs41_free_stateid(struct nfs_server *server, struct nfs4_state *state) | ||
6177 | { | ||
6178 | struct nfs4_exception exception = { }; | ||
6179 | int err; | ||
6180 | do { | ||
6181 | err = nfs4_handle_exception(server, | ||
6182 | _nfs4_free_stateid(server, state), | ||
6183 | &exception); | ||
6184 | } while (exception.retry); | ||
6185 | return err; | ||
6186 | } | ||
5906 | #endif /* CONFIG_NFS_V4_1 */ | 6187 | #endif /* CONFIG_NFS_V4_1 */ |
5907 | 6188 | ||
5908 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 6189 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { |
@@ -5939,8 +6220,8 @@ struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | |||
5939 | struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | 6220 | struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { |
5940 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 6221 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
5941 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 6222 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
5942 | .recover_open = nfs4_open_expired, | 6223 | .recover_open = nfs41_open_expired, |
5943 | .recover_lock = nfs4_lock_expired, | 6224 | .recover_lock = nfs41_lock_expired, |
5944 | .establish_clid = nfs41_init_clientid, | 6225 | .establish_clid = nfs41_init_clientid, |
5945 | .get_clid_cred = nfs4_get_exchange_id_cred, | 6226 | .get_clid_cred = nfs4_get_exchange_id_cred, |
5946 | }; | 6227 | }; |
@@ -5964,6 +6245,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { | |||
5964 | .minor_version = 0, | 6245 | .minor_version = 0, |
5965 | .call_sync = _nfs4_call_sync, | 6246 | .call_sync = _nfs4_call_sync, |
5966 | .validate_stateid = nfs4_validate_delegation_stateid, | 6247 | .validate_stateid = nfs4_validate_delegation_stateid, |
6248 | .find_root_sec = nfs4_find_root_sec, | ||
5967 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, | 6249 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, |
5968 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, | 6250 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, |
5969 | .state_renewal_ops = &nfs40_state_renewal_ops, | 6251 | .state_renewal_ops = &nfs40_state_renewal_ops, |
@@ -5974,6 +6256,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | |||
5974 | .minor_version = 1, | 6256 | .minor_version = 1, |
5975 | .call_sync = _nfs4_call_sync_session, | 6257 | .call_sync = _nfs4_call_sync_session, |
5976 | .validate_stateid = nfs41_validate_delegation_stateid, | 6258 | .validate_stateid = nfs41_validate_delegation_stateid, |
6259 | .find_root_sec = nfs41_find_root_sec, | ||
5977 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, | 6260 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, |
5978 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, | 6261 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, |
5979 | .state_renewal_ops = &nfs41_state_renewal_ops, | 6262 | .state_renewal_ops = &nfs41_state_renewal_ops, |
@@ -6002,6 +6285,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
6002 | .dentry_ops = &nfs4_dentry_operations, | 6285 | .dentry_ops = &nfs4_dentry_operations, |
6003 | .dir_inode_ops = &nfs4_dir_inode_operations, | 6286 | .dir_inode_ops = &nfs4_dir_inode_operations, |
6004 | .file_inode_ops = &nfs4_file_inode_operations, | 6287 | .file_inode_ops = &nfs4_file_inode_operations, |
6288 | .file_ops = &nfs4_file_operations, | ||
6005 | .getroot = nfs4_proc_get_root, | 6289 | .getroot = nfs4_proc_get_root, |
6006 | .getattr = nfs4_proc_getattr, | 6290 | .getattr = nfs4_proc_getattr, |
6007 | .setattr = nfs4_proc_setattr, | 6291 | .setattr = nfs4_proc_setattr, |