diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-02-07 14:26:21 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-02-11 15:33:14 -0500 |
commit | c21443c2c792cd9b463646d982b0fe48aa6feb0f (patch) | |
tree | c2d7f04beead6499390b5fffd842c76e248781da /fs/nfs | |
parent | 65b62a29f719e937b5be1df472287f4c61e53ac6 (diff) |
NFSv4: Fix a reboot recovery race when opening a file
If the server reboots after it has replied to our OPEN, but before we
call nfs4_opendata_to_nfs4_state(), then the reboot recovery thread
will not see a stateid for this open, and so will fail to recover it.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 50 |
1 files changed, 38 insertions, 12 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d51227371c67..7cbf7aa6c634 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -1848,6 +1848,43 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct | |||
1848 | sattr->ia_valid |= ATTR_MTIME; | 1848 | sattr->ia_valid |= ATTR_MTIME; |
1849 | } | 1849 | } |
1850 | 1850 | ||
1851 | static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | ||
1852 | fmode_t fmode, | ||
1853 | int flags, | ||
1854 | struct nfs4_state **res) | ||
1855 | { | ||
1856 | struct nfs4_state_owner *sp = opendata->owner; | ||
1857 | struct nfs_server *server = sp->so_server; | ||
1858 | struct nfs4_state *state; | ||
1859 | unsigned int seq; | ||
1860 | int ret; | ||
1861 | |||
1862 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); | ||
1863 | |||
1864 | ret = _nfs4_proc_open(opendata); | ||
1865 | if (ret != 0) | ||
1866 | goto out; | ||
1867 | |||
1868 | state = nfs4_opendata_to_nfs4_state(opendata); | ||
1869 | ret = PTR_ERR(state); | ||
1870 | if (IS_ERR(state)) | ||
1871 | goto out; | ||
1872 | if (server->caps & NFS_CAP_POSIX_LOCK) | ||
1873 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | ||
1874 | |||
1875 | ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags); | ||
1876 | if (ret != 0) | ||
1877 | goto out; | ||
1878 | |||
1879 | if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) { | ||
1880 | nfs4_schedule_stateid_recovery(server, state); | ||
1881 | nfs4_wait_clnt_recover(server->nfs_client); | ||
1882 | } | ||
1883 | *res = state; | ||
1884 | out: | ||
1885 | return ret; | ||
1886 | } | ||
1887 | |||
1851 | /* | 1888 | /* |
1852 | * Returns a referenced nfs4_state | 1889 | * Returns a referenced nfs4_state |
1853 | */ | 1890 | */ |
@@ -1892,18 +1929,7 @@ static int _nfs4_do_open(struct inode *dir, | |||
1892 | if (dentry->d_inode != NULL) | 1929 | if (dentry->d_inode != NULL) |
1893 | opendata->state = nfs4_get_open_state(dentry->d_inode, sp); | 1930 | opendata->state = nfs4_get_open_state(dentry->d_inode, sp); |
1894 | 1931 | ||
1895 | status = _nfs4_proc_open(opendata); | 1932 | status = _nfs4_open_and_get_state(opendata, fmode, flags, &state); |
1896 | if (status != 0) | ||
1897 | goto err_opendata_put; | ||
1898 | |||
1899 | state = nfs4_opendata_to_nfs4_state(opendata); | ||
1900 | status = PTR_ERR(state); | ||
1901 | if (IS_ERR(state)) | ||
1902 | goto err_opendata_put; | ||
1903 | if (server->caps & NFS_CAP_POSIX_LOCK) | ||
1904 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | ||
1905 | |||
1906 | status = nfs4_opendata_access(cred, opendata, state, fmode, flags); | ||
1907 | if (status != 0) | 1933 | if (status != 0) |
1908 | goto err_opendata_put; | 1934 | goto err_opendata_put; |
1909 | 1935 | ||